menuweb.t | documentation |
#charset "us-ascii" /* * TADS 3 Library - Menu System, console edition * * This implements the menusys user interface for the traditional * console-mode interpreters. */ #include "adv3.h" /* ------------------------------------------------------------------------ */ /* * Menu Item - user interface implementation for the console */ modify MenuItem /* * Call menu.display when you're ready to show the menu. This * should be called on the top-level menu; we run the entire menu * display process, and return when the user exits from the menu * tree. */ display() { /* save the top-level key list */ MenuItem.curKeyList = keyList; /* set myself as the current menu and the top-level menu */ MenuItem.topMenu = self; MenuItem.curMenu = self; /* display the menu in the javascript client */ showMenu(nil); /* process network events until the user closes the menu */ MenuItem.isOpen = true; processNetRequests({: !MenuItem.isOpen }); } /* current menu, and current top-level menu */ curMenu = nil topMenu = nil /* is the menu open? */ isOpen = nil /* show this menu as a submenu */ showMenu(from) { /* get the XML representation of the menu item list */ local xml = '<menusys><<getXML(from)>></menusys>'; /* tell the javascript client to display the menu */ webMainWin.sendWinEvent(xml); /* save this in the main window as the current menu state */ webMainWin.menuSysState = xml; } /* navigate into a submenu */ enterSubMenu(idx) { /* validate the index and select the new menu */ if (idx >= 1 && idx <= contents.length()) { /* get the new menu */ local m = contents[idx]; /* note the new menu location */ MenuItem.curMenu = m; /* show the new menu */ m.showMenu(self); } } /* * Package my menu items as XML, to send to the javascript API. * 'from' is the menu we just navigated from, if any. This is nil * when we enter the top level menu, since we're not navigating from * another menu; when we navigate from a parent to a child, this is * the parent; when we return from a child to a parent, this is the * child; and when we move directly from sibling to sibling (via a * next/previous chapter command), this is the sibling. When we * display a new topic in a topic list menu, this is simply 'self'. */ getXML(from) { /* set up a string buffer for the xml */ local s = new StringBuffer(); /* update the menu contents */ updateContents(); /* start with the menu title */ s.append('<title><<title.htmlify()>></title>'); /* note if we're the top-level menu */ if (location == nil || MenuItem.topMenu == self) s.append('<isTop/>'); /* run through the contents */ for (local item in contents) s.append('<menuItem><<item.title.htmlify()>></menuItem>'); /* if the 'from' menu is a child, initially select it */ local idx = contents.indexOf(from); if (idx != nil) s.append('<fromChild><<idx>></fromChild>'); /* add the keys */ getKeysXML(s); /* return the string */ return toString(s); } /* get the XML description of the top-level key list */ getKeysXML(buf) { buf.append('<keylists>'); for (local kl in curKeyList) { buf.append('<keylist>'); for (local k in kl) { if (k == ' ') k = 'U+0020'; buf.append('<key><<k>></key>'); } buf.append('</keylist>'); } buf.append('</keylists>'); } /* * Prepare a title or content string for our XML output. If 'val' is * a string, we'll run it through the output formatter to expand any * special <.xxx> sequences. If 'val' is a property, we'll evaluate * the property of self, capturing the output if it generates any or * capturing the string if it returns one. In all cases, we take the * result string and convert TADS special characters to HTML, and * finally html-escape the result for inclusion in XML output, and * return the resulting string. */ formatXML(func) { /* call the function and process it through the menu stream filters */ local txt = menuOutputStream.captureOutput(func); /* convert special characters and html-escape the result */ return txt.specialsToHtml().htmlify(); } ; /* * Menu system UI request processor. This receives requests from the * javascript client in response to user actions: selecting a menu item, * navigating to the parent menu, closing the menu. */ menuSysEventPage: WebResource vpath = '/webui/menusys' processRequest(req, query) { /* check the action type */ if (query.isKeyPresent('close')) { /* close the menu */ MenuItem.isOpen = nil; } else if (query.isKeyPresent('prev')) { /* go to the parent menu, or close the menu if at the top */ local cur = MenuItem.curMenu; if (cur != nil && cur != MenuItem.topMenu && cur.location != nil) { /* go to the parent */ local par = cur.location; MenuItem.curMenu = par; par.showMenu(cur); } else { /* there's no parent - close the menu */ MenuItem.isOpen = nil; /* tell the UI to close its menu dialog */ webMainWin.sendWinEvent('<menusys><close/></menusys>'); webMainWin.menuSysState = ''; } } else if (query.isKeyPresent('select')) { /* * Select a child menu. The 'select=n' parameter is the * index in the current menu's child list of the new item to * select. Retrieve the index. */ MenuItem.curMenu.enterSubMenu(toInteger(query['select'])); } else if (query.isKeyPresent('nextTopic')) { /* get the next topic in the current topic menu */ sendAck(req, MenuItem.curMenu.getNextTopicXML()); /* rebuild the menu state for the change */ webMainWin.menuSysState = '<menusys><<MenuItem.curMenu.getXML(MenuItem.curMenu) >></menusys>'; /* we've sent our reply, so we're done */ return; } else if (query.isKeyPresent('chapter')) { /* get the next or previous chapter, as applicable */ local dir = query['chapter']; local m = MenuItem.curMenu; local par = m.location; local nxt = (dir == 'next' ? par.getNextMenu(m) : par.getPrevMenu(m)); /* enter this chapter */ if (nxt != nil) { MenuItem.curMenu = nxt; nxt.showMenu(m); } } /* acknowledge the request */ sendAck(req); } ; /* ------------------------------------------------------------------------ */ /* * Menu topic item - console UI implementation */ modify MenuTopicItem /* get the XML description of my menu list */ getXML(from) { /* start with an empty result buffer */ local s = new StringBuffer(); /* update our contents, as needed */ updateContents(); /* add the title and total number of items in the menu */ s.append('<title><<title.htmlify()>></title>' + '<numItems><<menuContents.length()>></numItems>'); /* note if we're the top-level menu */ if (location == nil || MenuItem.topMenu == self) s.append('<isTop/>'); /* add each item in our list */ for (local i in 1..lastDisplayed) s.append(getTopicXML(i)); /* add the keys */ getKeysXML(s); /* return the XML string */ return toString(s); } /* get the next topic, in XML format */ getNextTopicXML() { /* if we're not already at the last item, advance the counter */ if (lastDisplayed < menuContents.length()) ++lastDisplayed; /* format the last item */ return getTopicXML(lastDisplayed); } /* get the XML formatted description of the item at the given index */ getTopicXML(i) { /* get the item */ local item = menuContents[i]; /* get the item's text, and format as XML */ item = formatXML(dataType(item) == TypeObject ? {: item.getItemText() } : item); /* format the item text */ return '<topicItem><<item>></topicItem>'; } ; /* ------------------------------------------------------------------------ */ /* * Long topic item */ modify MenuLongTopicItem /* get my XML description */ getXML(from) { /* start with an empty result buffer */ local s = new StringBuffer(); /* update our contents, as needed */ updateContents(); /* add my title (heading) */ local t = heading != nil && heading != '' ? heading : title; s.append('<title><<t.htmlify()>></title>'); /* add our contents */ s.append('<longTopic><<formatXML({: menuContents })>></longTopic>'); /* * if this is a chapter menu, note if we have links for the next * and previous chapters */ if (isChapterMenu) { local m; if ((m = location.getNextMenu(self)) != nil) s.append('<nextChapter><<m.title.htmlify()>></nextChapter>'); if ((m = location.getPrevMenu(self)) != nil) s.append('<prevChapter><<m.title.htmlify()>></prevChapter>'); } /* add the keys */ getKeysXML(s); /* return the XML string */ return toString(s); } ;
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3
Generated on 5/16/2013 from TADS version 3.1.3