{ /* ENiGMA½ Menu Configuration This configuration is in HJSON format. Strict to-spec JSON is also perfectly valid. The hjson npm can be used to convert to/from JSON. See http://hjson.org/ for more information and syntax. */ menus: { // // Send telnet connections to matrix where users can login, apply, etc. // telnetConnected: { art: CONNECT next: matrix options: { nextTimeout: 1500 } } // // SSH connections are pre-authenticated via the SSH server itself. // Jump directly to the login sequence // sshConnected: { art: CONNECT next: fullLoginSequenceLoginArt options: { nextTimeout: 1500 } } // // Another SSH specialization: If the user logs in with a new user // name (e.g. "new", "apply", ...) they will be directed to the // application process. // sshConnectedNewUser: { art: CONNECT next: newUserApplicationSsh options: { nextTimeout: 1500 } } // Ye ol' standard matrix matrix: { art: matrix form: { 0: { VM: { mci: { VM1: { submit: true focus: true // :TODO: need a good way to localize these ... Standard Orig->Lookup seems good. items: [ "login", "apply", "log off" ] } } submit: { *: [ { value: { 1: 0 } action: @menu:login } { value: { 1: 1 }, action: @menu:newUserApplication } { value: { 1: 2 }, action: @menu:logoff } ] } } } } } login: { art: USERLOG next: fullLoginSequenceLoginArt config: { tooNode: { art: TOONODE } } form: { 0: { mci: { ET1: { maxLength: @config:users.usernameMax argName: username focus: true } ET2: { password: true maxLength: @config:users.passwordMax argName: password submit: true } } submit: { *: [ { value: { password: null } action: @systemMethod:login } ] } actionKeys: [ { keys: [ "escape" ] action: @systemMethod:prevMenu } ] } } } logoff: { art: LOGOFF next: @systemMethod:logoff } /* TODO: display PRINT before this (Obv/2) or NEWUSER1 (Mystic) */ newUserApplication: { art: NUA next: newUserFeedbackToSysOpPreamble form: { 0: { mci: { ET1: { focus: true argName: username maxLength: @config:users.usernameMax } ET2: { argName: realName maxLength: 32 } MET3: { argName: birthdate maskPattern: "####/##/##" } ME4: { argName: sex maskPattern: A textStyle: upper } ET5: { argName: location maxLength: 32 } ET6: { argName: affils maxLength: 32 } ET7: { argName: email maxLength: 255 } ET8: { argName: web maxLength: 255 } ET9: { argName: password password: true maxLength: @config:users.passwordMax } ET10: { argName: passwordConfirm password: true maxLength: @config:users.passwordMax } TM12: { argName: submission items: [ "apply", "cancel" ] submit: true } } submit: { *: [ { value: { "submission" : 0 } action: @method:apply/submitApplication extraArgs: { inactive: userNeedsActivated error: newUserCreateError } } { value: { "submission" : 1 } action: @systemMethod:prevMenu } ] } actionKeys: [ { keys: [ "escape" ] action: @systemMethod:prevMenu } ] } } } // SSH specialization of NUA newUserApplicationSsh: { art: NUA fallback: logoff next: newUserFeedbackToSysOpPreamble form: { 0: { mci: { ET1: { focus: true argName: username maxLength: @config:users.usernameMax } ET2: { argName: realName maxLength: 32 } MET3: { argName: birthdate maskPattern: "####/##/##" } ME4: { argName: sex maskPattern: A textStyle: upper } ET5: { argName: location maxLength: 32 } ET6: { argName: affils maxLength: 32 } ET7: { argName: email maxLength: 255 } ET8: { argName: web maxLength: 255 } ET9: { argName: password password: true maxLength: @config:users.passwordMax } ET10: { argName: passwordConfirm password: true maxLength: @config:users.passwordMax } TM12: { argName: submission items: [ "apply", "cancel" ] submit: true } } submit: { *: [ { value: { "submission" : 0 } action: @method:apply/submitApplication extraArgs: { inactive: userNeedsActivated error: newUserCreateError } } { value: { "submission" : 1 } action: @systemMethod:prevMenu } ] } actionKeys: [ { keys: [ "escape" ] action: @systemMethod:prevMenu } ] } } } newUserFeedbackToSysOpPreamble: { art: LETTER options: { pause: true } next: newUserFeedbackToSysOp extraArgs: { messageAreaName: private_mail } } newUserFeedbackToSysOp: { status: Feedback to SysOp module: msg_area_post_fse next: [ { acs: AS2 next: fullLoginSequenceLoginArt } { // acs: !AS2 next: newUserInactiveDone } ] config: { art: { header: MSGEHDR body: MSGBODY footerEditor: MSGEFTR footerEditorMenu: MSGEMFT help: MSGEHLP }, editorMode: edit editorType: area } form: { 0: { mci: { TL1: { argName: from } ET2: { argName: to focus: true text: @config:general.sysOp.username // :TODO: readOnly: true } ET3: { argName: subject maxLength: 72 submit: true text: New user feedback } } submit: { 3: [ { value: { subject: null } action: @method:headerSubmit } ] } } 1: { mci: { MT1: { width: 79 argName: message mode: edit } } submit: { *: [ { value: "message", action: "@method:editModeEscPressed" } ] } actionKeys: [ { keys: [ "escape" ] viewId: 1 } ] }, 2: { TLTL: { mci: { TL1: { width: 5 } TL2: { width: 4 } } } } 3: { HM: { mci: { HM1: { // :TODO: clear items: [ "save", "help" ] } } submit: { *: [ { value: { 1: 0 } action: @method:editModeMenuSave } { value: { 1: 1 } action: @method:editModeMenuHelp } ] } actionKeys: [ { keys: [ "escape" ] action: @method:editModeEscPressed } { keys: [ "?" ] action: @method:editModeMenuHelp } ] } } } } newUserInactiveDone: { desc: Finished with NUA art: DONE options: { pause: true } next: @menu:logoff } fullLoginSequenceLoginArt: { desc: Logging In art: WELCOME options: { pause: true } next: fullLoginSequenceLastCallers } fullLoginSequenceLastCallers: { desc: Last Callers module: last_callers art: LASTCALL options: { pause: true } next: fullLoginSequenceSysStats } fullLoginSequenceSysStats: { desc: System Stats art: SYSSTAT options: { pause: true } next: fullLoginSequenceUserStats } fullLoginSequenceUserStats: { desc: User Stats art: STATUS options: { pause: true } next: mainMenu } /////////////////////////////////////////////////////////////////////// // Main Menu /////////////////////////////////////////////////////////////////////// mainMenu: { art: MMENU desc: Main Menu prompt: menuCommand submit: [ { value: { command: "G" } action: @menu:logoff } { value: { command: "D" } action: @menu:doorMenu } { value: { command: "U" } action: @menu:mainMenuUserList } { value: { command: "L" } action: @menu:mainMenuLastCallers } { value: { command: "Y" } action: @menu:mainMenuUserStats } { value: { command: "M" } action: @menu:messageArea } { value: { command: "C" } action: @menu:mainMenuUserConfig } { value: { command: "S" } action: @menu:mainMenuSystemStats } { value: 1 action: @menu:mainMenu } ] } mainMenuLastCallers: { desc: Last Callers module: last_callers art: LASTCALL options: { pause: true } } mainMenuUserStats: { desc: User Stats art: STATUS options: { pause: true } } mainMenuSystemStats: { desc: System Stats art: SYSSTAT options: { pause: true } } mainMenuUserList: { desc: User Listing module: user_list art: USERLST form: { 0: { mci: { VM1: { focus: true submit: true } } actionKeys: [ { keys: [ "escape", "q", "shift + q" ] action: @systemMethod:prevMenu } ] } } } mainMenuUserConfig: { module: @systemModule:user_config art: CONFSCR form: { 0: { mci: { ET1: { argName: email } ET2: { argName: location } ET3: { argName: webAddress } ET4: { argName: affils } ME5: { maskPattern: "####/##/##" argName: birthdate } ME11: { maskPattern: "##x##" argName: termSize } } actionKeys: [ { keys: [ "escape" ] action: @method:exitKeyPressed } ] } } } /////////////////////////////////////////////////////////////////////// // Doors Menu /////////////////////////////////////////////////////////////////////// doorMenu: { desc: Doors Menu art: DOORMNU prompt: menuCommand submit: [ { value: { command: "G" } action: @menu:logoff } { value: { command: "Q" } action: @systemMethod:prevMenu } { value: { command: "1" } action: @menu:doorPimpWars } { value: { command: "2" } action: @menu:doorLORD } ] } /* The 'abracadabra' module's config.args accepts the following format objects: {dropfile} - Path to generated dropfile {node} - Node number */ doorPimpWars: { desc: Playing PimpWars module: abracadabra config: { name: PimpWars dropFileType: DORINFO cmd: /usr/bin/dosemu args: [ "-quiet", "-f", "/home/nuskooler/DOS/X/LORD/dosemu.conf", "X:\\PW\\START.BAT {dropfile} {node}" ], nodeMax: 1 tooManyArt: DOORMANY } }, doorLORD: { desc: Playing L.O.R.D. module: abracadabra config: { name: LORD dropFileType: DOOR cmd: /usr/bin/dosemu args: [ "-quiet", "-f", "/home/nuskooler/DOS/X/LORD/dosemu.conf", "X:\\LORD\\START.BAT {node}" ] } } /////////////////////////////////////////////////////////////////////// // Message Area Menu /////////////////////////////////////////////////////////////////////// messageArea: { module: msg_area art: MSGMNU desc: Message Area prompt: menuCommand submit: [ { value: { command: "P" } action: @menu:messageAreaNewPost } { value: { command: "C" } action: @menu:messageAreaChangeCurrentArea } { value: { command: "L" } action: @menu:messageAreaMessageList } { value: { command: "Q" } action: @systemMethod:prevMenu } { value: { command: "G" } action: @menu:logoff } { value: 1 action: @menu:messageArea } ] } messageAreaChangeCurrentArea: { art: CHANGE module: msg_area_list form: { 0: { mci: { VM1: { focus: true submit: true argName: area } } submit: { *: [ { value: { area: null } action: @method:changeArea } ] } actionKeys: [ { keys: [ "escape", "q", "shift + q" ] action: @systemMethod:prevMenu } ] } } } messageAreaMessageList: { module: msg_list art: MSGLIST config: { listType: public menuViewPost: messageAreaViewPost } form: { 0: { mci: { VM1: { focus: true submit: true argName: message } } submit: { *: [ { value: { message: null } action: @method:selectMessage } ] } actionKeys: [ { keys: [ "escape", "q", "shift + q" ] action: @systemMethod:prevMenu } ] } } } messageAreaViewPost: { module: msg_area_view_fse config: { art: { header: MSGVHDR body: MSGBODY footerView: MSGVFTR help: MSGVHLP }, editorMode: view editorType: area } form: { 0: { mci: { // :TODO: ensure this block isn't even req. for theme to apply... } } 1: { mci: { MT1: { width: 79 mode: preview } } submit: { *: [ { value: message action: @method:editModeEscPressed } ] } actionKeys: [ { keys: [ "escape" ] viewId: 1 } ] } 2: { TLTL: { mci: { TL1: { width: 5 } TL2: { width: 4 } } } } 4: { mci: { HM1: { // :TODO: (#)Jump/(L)Index (msg list)/Last items: [ "prev", "next", "reply", "quit", "help" ] } } submit: { *: [ { value: { 1: 0 } action: @method:prevMessage } { value: { 1: 1 } action: @method:nextMessage } { value: { 1: 2 } action: @method:replyMessage extraArgs: { menu: messageAreaReplyPost } } { value: { 1: 3 } action: @menu:messageArea } { value: { 1: 4 } action: @method:viewModeMenuHelp } ] } actionKeys: [ { keys: [ "p", "shift + p" ] action: @method:prevMessage } { keys: [ "n", "shift + n" ] action: @method:nextMessage } { keys: [ "r", "shift + r" ] action: @method:replyMessage extraArgs: { menu: messageAreaReplyPost } } { keys: [ "escape", "q", "shift + q" ] action: @systemMethod:prevMenu } { keys: [ "?" ] action: @method:viewModeMenuHelp } { keys: [ "down arrow", "up arrow", "page up", "page down" ] action: @method:movementKeyPressed } ] } } }, messageAreaReplyPost: { module: msg_area_post_fse config: { art: { header: MSGEHDR body: MSGBODY quote: MSGQUOT footerEditor: MSGEFTR footerEditorMenu: MSGEMFT help: MSGEHLP } editorMode: edit editorType: area } form: { 0: { mci: { // :TODO: use appropriate system properties for max lengths TL1: { argName: from } ET2: { argName: to focus: true } ET3: { argName: subject maxLength: 72 submit: true } TL4: { // :TODO: this is for RE: line (NYI) //width: 27 //textOverflow: ... } } submit: { 3: [ { "value" : { "subject" : null }, "action" : "@method:headerSubmit" } ] } } 1: { mci: { MT1: { width: 79 height: 14 argName: message mode: edit } } submit: { *: [ { "value": "message", "action": "@method:editModeEscPressed" } ] } actionKeys: [ { keys: [ "escape" ], viewId: 1 } ] } 3: { HM: { mci: { HM1: { items: [ "save", "discard", "quote", "help" ] } } submit: { *: [ { value: { 1: 0 } action: @method:editModeMenuSave } { value: { 1: 1 } action: @systemMethod:prevMenu } { value: { 1: 2 }, action: @method:editModeMenuQuote } { value: { 1: 3 } action: @method:editModeMenuHelp } ] } actionKeys: [ { keys: [ "escape" ] action: @method:editModeEscPressed } { keys: [ "s", "shift + s" ] action: @method:editModeMenuSave } { keys: [ "d", "shift + d" ] action: @systemMethod:prevMenu } { keys: [ "q", "shift + q" ] action: @method:editModeMenuQuote } { keys: [ "?" ] action: @method:editModeMenuHelp } ] } } // Quote builder 5: { mci: { MT1: { width: 79 height: 7 } VM3: { width: 79 height: 4 argName: quote } } submit: { *: [ { value: { quote: null } action: @method:appendQuoteEntry } ] } actionKeys: [ { keys: [ "escape" ] action: @method:quoteBuilderEscPressed } ] } } } // :TODO: messageAreaSelect (change msg areas -> call @systemMethod -> fallback to menu messageAreaNewPost: { status: Posting message, module: msg_area_post_fse config: { art: { header: MSGEHDR body: MSGBODY footerEditor: MSGEFTR footerEditorMenu: MSGEMFT help: MSGEHLP } editorMode: edit editorType: area } form: { 0: { mci: { TL1: { argName: from } ET2: { argName: to focus: true text: All } ET3: { argName: subject maxLength: 72 submit: true } } submit: { 3: [ { value: { subject: null } action: @method:headerSubmit } ] } } 1: { "mci" : { MT1: { width: 79 argName: message mode: edit } } submit: { *: [ { "value": "message", "action": "@method:editModeEscPressed" } ] } actionKeys: [ { keys: [ "escape" ] viewId: 1 } ] } 2: { TLTL: { mci: { TL1: { width: 5 } TL2: { width: 4 } } } } 3: { HM: { mci: { HM1: { // :TODO: clear "items" : [ "save", "discard", "help" ] } } submit: { *: [ { value: { 1: 0 } action: @method:editModeMenuSave } { value: { 1: 1 } action: @systemMethod:prevMenu } { value: { 1: 2 } action: @method:editModeMenuHelp } ] } actionKeys: [ { keys: [ "escape" ] action: @method:editModeEscPressed } { keys: [ "?" ] action: @method:editModeMenuHelp } ] // :TODO: something like the following for overriding keymap // this should only override specified entries. others will default /* "keyMap" : { "accept" : [ "return" ] } */ } } } } //////////////////////////////////////////////////////////////////////// // Required entries //////////////////////////////////////////////////////////////////////// idleLogoff: { art: IDLELOG next: @systemMethod:logoff } //////////////////////////////////////////////////////////////////////// // Demo Section // :TODO: This entire section needs updated!!! //////////////////////////////////////////////////////////////////////// "demoMain" : { "art" : "demo_selection_vm.ans", "form" : { "0" : { "VM" : { "mci" : { "VM1" : { "items" : [ "Single Line Text Editing Views", "Spinner & Toggle Views", "Mask Edit Views", "Multi Line Text Editor", "Vertical Menu Views", "Horizontal Menu Views", "Art Display", "Full Screen Editor" ], "height" : 10, "itemSpacing" : 1, "justify" : "center", "focusTextStyle" : "small i" } }, "submit" : { "*" : [ { "value" : { "1" : 0 }, "action" : "@menu:demoEditTextView" }, { "value" : { "1" : 1 }, "action" : "@menu:demoSpinAndToggleView" }, { "value" : { "1" : 2 }, "action" : "@menu:demoMaskEditView" }, { "value" : { "1" : 3 }, "action" : "@menu:demoMultiLineEditTextView" }, { "value" : { "1" : 4 }, "action" : "@menu:demoVerticalMenuView" }, { "value" : { "1" : 5 }, "action" : "@menu:demoHorizontalMenuView" }, { "value" : { "1" : 6 }, "action" : "@menu:demoArtDisplay" }, { "value" : { "1" : 7 }, "action" : "@menu:demoFullScreenEditor" } ] } } } } }, "demoEditTextView" : { "art" : "demo_edit_text_view1.ans", "form" : { "0" : { "BTETETETET" : { "mci" : { "ET1" : { "width" : 20, "maxLength" : 20 }, "ET2" : { "width" : 20, "maxLength" : 40, "textOverflow" : "..." }, "ET3" : { "width" : 20, "fillChar" : "-", "styleSGR1" : "|00|36", "maxLength" : 20 }, "ET4" : { "width" : 20, "maxLength" : 20, "password" : true }, "BT5" : { "width" : 8, "text" : "< Back" } }, "submit" : { "*" : [ { "value" : 5, "action" : "@menu:demoMain" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 5 } ] } } } }, "demoSpinAndToggleView" : { "art" : "demo_spin_and_toggle.ans", "form" : { "0" : { "BTSMSMTM" : { "mci" : { "SM1" : { "items" : [ "Henry Morgan", "François l'Ollonais", "Roche Braziliano", "Black Bart", "Blackbeard" ] }, "SM2" : { "items" : [ "Razor 1911", "DrinkOrDie", "TRSI" ] }, "TM3" : { "items" : [ "Yarly", "Nowaii" ], "styleSGR1" : "|00|30|01", "hotKeys" : { "Y" : 0, "N" : 1 } }, "BT8" : { "text" : "< Back" } }, "submit" : { "*" : [ { "value" : 8, "action" : "@menu:demoMain" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 8 } ] } } } }, "demoMaskEditView" : { "art" : "demo_mask_edit_text_view1.ans", "form" : { "0" : { "BTMEME" : { "mci" : { "ME1" : { "maskPattern" : "##/##/##", "styleSGR1" : "|00|30|01", //"styleSGR2" : "|00|45|01", "styleSGR3" : "|00|30|35", "fillChar" : "#" }, "BT5" : { "text" : "< Back" } }, "submit" : { "*" : [ { "value" : 5, "action" : "@menu:demoMain" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 5 } ] } } } }, "demoMultiLineEditTextView" : { "art" : "demo_multi_line_edit_text_view1.ans", "form" : { "0" : { "BTMT" : { "mci" : { "MT1" : { "width" : 70, "height" : 17, //"text" : "@art:demo_multi_line_edit_text_view_text.txt", // "text" : "@systemMethod:textFromFile" text: "Hints:\n\t* Insert / CTRL-V toggles overtype mode\n\t* CTRL-Y deletes the current line\n\t* Try Page Up / Page Down\n\t* Home goes to the start of line text\n\t* End goes to the end of a line\n\n\nTab handling:\n-------------------------------------------------\n\tA\tB\tC\tD\tE\tF\nA\tB\tC\tD\tE\tF\tG\tH\n\tA\tB\tC\tD\tE\tF\nA\tB\tC\tD\tE\tF\tG\tH\nA0\tBB\t1\tCCC\t2\tDDD\t3EEEE\nW\t\tX\t\tY\t\tZ\n\nAn excerpt from A Clockwork Orange:\n\"What sloochatted then, of course, was that my cellmates woke up and started joining in, tolchocking a bit wild in the near-dark, and the shoom seemed to wake up the whole tier, so that you could slooshy a lot of creeching and banging about with tin mugs on the wall, as though all the plennies in all the cells thought a big break was about to commence, O my brothers.\n", "focus" : true }, "BT5" : { "text" : "< Back" } }, "submit" : { "*" : [ { "value" : 5, "action" : "@menu:demoMain" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 5 } ] } } } }, "demoHorizontalMenuView" : { "art" : "demo_horizontal_menu_view1.ans", "form" : { "0" : { "BTHMHM" : { "mci" : { "HM1" : { "items" : [ "One", "Two", "Three" ], "hotKeys" : { "1" : 0, "2" : 1, "3" : 2 } }, "HM2" : { "items" : [ "Uno", "Dos", "Tres" ], "hotKeys" : { "U" : 0, "D" : 1, "T" : 2 } }, "BT5" : { "text" : "< Back" } }, "submit" : { "*" : [ { "value" : 5, "action" : "@menu:demoMain" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 5 } ] } } } }, "demoVerticalMenuView" : { "art" : "demo_vertical_menu_view1.ans", "form" : { "0" : { "BTVM" : { "mci" : { "VM1" : { "items" : [ "|33Oblivion/2", "|33iNiQUiTY", "|33ViSiON/X" ], "focusItems" : [ "|33Oblivion|01/|00|332", "|01|33i|00|33N|01i|00|33QU|01i|00|33TY", "|33ViSiON/X" ] // // :TODO: how to do the following: // 1) Supply a view a string for a standard vs focused item // "items" : [...], "focusItems" : [ ... ] ? // "draw" : "@method:drawItemX", then items: [...] }, "BT5" : { "text" : "< Back" } }, "submit" : { "*" : [ { "value" : 5, "action" : "@menu:demoMain" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 5 } ] } } } }, "demoArtDisplay" : { "art" : "demo_selection_vm.ans", "form" : { "0" : { "VM" : { "mci" : { "VM1" : { "items" : [ "Defaults - DOS ANSI", "bw_mindgames.ans - DOS", "test.ans - DOS", "Defaults - Amiga", "Pause at Term Height" ], // :TODO: justify not working?? "focusTextStyle" : "small i" } }, "submit" : { "*" : [ { "value" : { "1" : 0 }, "action" : "@menu:demoDefaultsDosAnsi" }, { "value" : { "1" : 1 }, "action" : "@menu:demoDefaultsDosAnsi_bw_mindgames" }, { "value" : { "1" : 2 }, "action" : "@menu:demoDefaultsDosAnsi_test" } ] } } } } }, "demoDefaultsDosAnsi" : { "art" : "DM-ENIG2.ANS" }, "demoDefaultsDosAnsi_bw_mindgames" : { "art" : "bw_mindgames.ans" }, "demoDefaultsDosAnsi_test" : { "art" : "test.ans" }, "demoFullScreenEditor" : { "module" : "@systemModule:fse", "config" : { "editorType" : "netMail", "art" : { "header" : "demo_fse_netmail_header.ans", "body" : "demo_fse_netmail_body.ans", "footerEditor" : "demo_fse_netmail_footer_edit.ans", "footerEditorMenu" : "demo_fse_netmail_footer_edit_menu.ans", "footerView" : "demo_fse_netmail_footer_view.ans", "help" : "demo_fse_netmail_help.ans" } }, "form" : { "0" : { "ETETET" : { "mci" : { "ET1" : { // :TODO: from/to may be set by args // :TODO: focus may change dep on view vs edit "width" : 36, "focus" : true, "argName" : "to" }, "ET2" : { "width" : 36, "argName" : "from" }, "ET3" : { "width" : 65, "maxLength" : 72, "submit" : [ "enter" ], "argName" : "subject" } }, "submit" : { "3" : [ { "value" : { "subject" : null }, "action" : "@method:headerSubmit" } ] } } }, "1" : { "MT" : { "mci" : { "MT1" : { "width" : 79, "height" : 17, "text" : "", // :TODO: should not be req. "argName" : "message" } }, "submit" : { "*" : [ { "value" : "message", "action" : "@method:editModeEscPressed" } ] }, "actionKeys" : [ { "keys" : [ "escape" ], "viewId" : 1 } ] } }, "2" : { "TLTL" : { "mci" : { "TL1" : { "width" : 5 }, "TL2" : { "width" : 4 } } } }, "3" : { "HM" : { "mci" : { "HM1" : { // :TODO: Continue, Save, Discard, Clear, Quote, Help "items" : [ "Save", "Discard", "Quote", "Help" ] } }, "submit" : { "*" : [ { "value" : { "1" : 0 }, "action" : "@method:editModeMenuSave" }, { "value" : { "1" : 1 }, "action" : "@menu:demoMain" }, { "value" : { "1" : 2 }, "action" : "@method:editModeMenuQuote" }, { "value" : { "1" : 3 }, "action" : "@method:editModeMenuHelp" }, { "value" : 1, "action" : "@method:editModeEscPressed" } ] }, "actionKeys" : [ // :TODO: Need better name { "keys" : [ "escape" ], "action" : "@method:editModeEscPressed" } ] } } } } } }