* Moved menus -> menus.json::menus

* Move prompts -> prompts.json::prompts
* Default to 80x25 if NAWS/ENV/CPR term size negotiations fail. Seeing this with Netrunner. May need more work.
This commit is contained in:
Bryan Ashby 2015-05-15 23:02:58 -06:00
parent 9ac2e9af6e
commit 0d9add70bd
8 changed files with 511 additions and 454 deletions

View File

@ -454,6 +454,7 @@ function display(options, cb) {
var nextPauseTermHeight = options.client.term.termHeight; var nextPauseTermHeight = options.client.term.termHeight;
var continous = false; var continous = false;
/*
parser.on('row update', function rowUpdate(row) { parser.on('row update', function rowUpdate(row) {
if(row >= nextPauseTermHeight) { if(row >= nextPauseTermHeight) {
if(!continous && 'termHeight' === options.pause) { if(!continous && 'termHeight' === options.pause) {
@ -469,6 +470,7 @@ function display(options, cb) {
nextPauseTermHeight += options.client.term.termHeight; nextPauseTermHeight += options.client.term.termHeight;
} }
}); });
*/
parser.on('mci', function mciEncountered(mciInfo) { parser.on('mci', function mciEncountered(mciInfo) {

View File

@ -14,33 +14,56 @@ var util = require('util');
exports.connectEntry = connectEntry; exports.connectEntry = connectEntry;
function ansiQueryTermSizeIfNeeded(client) { function ansiQueryTermSizeIfNeeded(client, cb) {
if(client.term.termHeight > 0 || client.term.termWidth > 0) { if(client.term.termHeight > 0 || client.term.termWidth > 0) {
cb(true);
return; return;
} }
var onCPR = function(pos) { var cprListener = function(pos) {
// //
// If we've already found out, disregard // If we've already found out, disregard
// //
if(client.term.termHeight > 0 || client.term.termWidth > 0) { if(client.term.termHeight > 0 || client.term.termWidth > 0) {
cb(true);
return; return;
} }
assert(2 === pos.length); assert(2 === pos.length);
client.term.termHeight = pos[0]; var h = pos[0];
client.term.termWidth = pos[1]; var w = pos[1];
//
// Netrunner for example gives us 1x1 here. Not really useful. Ignore
// values that seem obviously bad.
//
if(h < 10 || w < 10) {
Log.warn(
{ height : h, width : w },
'Ignoring ANSI CPR screen size query response due to very small values');
cb(false);
return;
}
client.term.termHeight = h;
client.term.termWidth = w;
Log.debug( Log.debug(
{ termWidth : client.term.termWidth, termHeight : client.term.termHeight, updateSource : 'ANSI CPR' }, {
'Window size updated'); termWidth : client.term.termWidth,
termHeight : client.term.termHeight,
source : 'ANSI CPR'
},
'Window size updated'
);
}; };
client.once('cursor position report', onCPR); client.once('cursor position report', cprListener);
// give up after 2s // give up after 2s
setTimeout(function onTimeout() { setTimeout(function onTimeout() {
client.removeListener('cursor position report', onCPR); client.removeListener('cursor position report', cprListener);
cb(true);
}, 2000); }, 2000);
client.term.write(ansi.queryScreenSize()); client.term.write(ansi.queryScreenSize());
@ -53,10 +76,10 @@ function prepareTerminal(term) {
} }
function displayBanner(term) { function displayBanner(term) {
// :TODO: add URL to banner // :TODO: add URL(s) to banner
term.write(ansi.fromPipeCode(util.format('' + term.write(ansi.fromPipeCode(util.format('' +
'|33Conected to |32EN|33|01i|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' + '|33Conected to |32EN|33|01i|00|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
'|00|33Copyright (c) 2014 Bryan Ashby\n' + '|00|33Copyright (c) 2014-2015 Bryan Ashby\n' +
'|00', packageJson.version))); '|00', packageJson.version)));
} }
@ -67,17 +90,30 @@ function connectEntry(client) {
// If we don't yet know the client term width/height, // If we don't yet know the client term width/height,
// try with a nonstandard ANSI DSR type request. // try with a nonstandard ANSI DSR type request.
// //
ansiQueryTermSizeIfNeeded(client); ansiQueryTermSizeIfNeeded(client, function ansiCprResult(result) {
prepareTerminal(term); if(!result) {
//
// We still don't have something good for term height/width.
// Default to DOS size 80x25.
//
// :TODO: Netrunner is currenting hitting this and it feels wrong. Why is NAWS/ENV/CPR all failing???
Log.warn('Failed to negotiate term size; Defaulting to 80x25!');
term.termHeight = 25;
term.termWidth = 80;
}
// prepareTerminal(term);
// Always show a ENiGMA½ banner
//
displayBanner(term);
setTimeout(function onTimeout() { //
client.gotoMenuModule( { name : Config.firstMenu }); // Always show a ENiGMA½ banner
}, 500); //
displayBanner(term);
setTimeout(function onTimeout() {
client.gotoMenuModule( { name : Config.firstMenu });
}, 500);
});
} }

View File

@ -37,7 +37,7 @@ function MaskEditTextView(options) {
this.maskPattern = options.maskPattern || ''; this.maskPattern = options.maskPattern || '';
this.clientBackspace = function() { this.clientBackspace = function() {
var fillCharSGR = this.getStyleSGR(2) || this.getSGR(); var fillCharSGR = this.getStyleSGR(3) || this.getSGR();
this.client.term.write('\b' + fillCharSGR + this.fillChar + '\b' + this.getFocusSGR()); this.client.term.write('\b' + fillCharSGR + this.fillChar + '\b' + this.getFocusSGR());
}; };
@ -55,10 +55,11 @@ function MaskEditTextView(options) {
self.client.term.write((self.hasFocus ? self.getFocusSGR() : self.getSGR()) + textToDraw[t]); self.client.term.write((self.hasFocus ? self.getFocusSGR() : self.getSGR()) + textToDraw[t]);
t++; t++;
} else { } else {
self.client.term.write((self.getStyleSGR(2) || '') + self.fillChar); self.client.term.write((self.getStyleSGR(3) || '') + self.fillChar);
} }
} else { } else {
self.client.term.write((self.getStyleSGR(1) || '') + self.maskPattern[i]); var styleSgr = this.hasFocus ? (self.getStyleSGR(2) || '') : (self.getStyleSGR(1) || '');
self.client.term.write(styleSgr + self.maskPattern[i]);
} }
i++; i++;
} }
@ -79,6 +80,10 @@ function MaskEditTextView(options) {
} }
}; };
this.getCursorEditYPosition = function() {
return this.position.y + this.patternArrayPos;
};
this.buildPattern(); this.buildPattern();
} }
@ -92,6 +97,21 @@ MaskEditTextView.maskPatternCharacterRegEx = {
'&' : /[\w\d\s]/, // Any "printable" 32-126, 128-255 '&' : /[\w\d\s]/, // Any "printable" 32-126, 128-255
}; };
MaskEditTextView.prototype.setFocus = function(focused) {
// :TODO: can't call super unless we want wasted redraw stuff. This seems sloppy & should probably be looked into
//MaskEditTextView.super_.prototype.setFocus.call(this, focused);
assert(this.acceptsFocus, 'View does not accept focus');
this.hasFocus = focused;
this.restoreCursor();
this.redraw();
// position & SGR for cursor
this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition()));
this.client.term.write(this.getFocusSGR());
};
MaskEditTextView.prototype.setMaskPattern = function(pattern) { MaskEditTextView.prototype.setMaskPattern = function(pattern) {
this.dimens.width = pattern.length; this.dimens.width = pattern.length;
@ -123,8 +143,8 @@ MaskEditTextView.prototype.onKeyPress = function(key, isSpecial) {
} }
this.redraw(); this.redraw();
} this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition()));
}
MaskEditTextView.super_.prototype.onKeyPress.call(this, key, isSpecial); MaskEditTextView.super_.prototype.onKeyPress.call(this, key, isSpecial);
}; };
@ -140,21 +160,14 @@ MaskEditTextView.prototype.onSpecialKeyPress = function(keyName) {
this.text = this.text.substr(0, this.text.length - 1); this.text = this.text.substr(0, this.text.length - 1);
this.clientBackspace(); this.clientBackspace();
} else { } else {
var offset = -1;
while(this.patternArrayPos > 0) { while(this.patternArrayPos > 0) {
if(_.isRegExp(this.patternArray[this.patternArrayPos])) { if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
this.text = this.text.substr(0, this.text.length - 1); this.text = this.text.substr(0, this.text.length - 1);
this.client.term.write(ansi.goto(this.position.x, this.position.y + (this.text.length - offset))); this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition() + 1));
// :TODO: use better ANSI Position code to just go back
// this.client.term.write(ansi.goto(this.position.x, yPosition));
this.clientBackspace(); this.clientBackspace();
break; break;
} }
console.log('skip past ' + this.patternArray[this.patternArrayPos])
//this.client.term.write(ansi.back() + ansi.back());
this.patternArrayPos--; this.patternArrayPos--;
offset++;
} }
} }
} }

View File

@ -48,8 +48,8 @@ function getMenuConfig(name, cb) {
}); });
}, },
function locateMenuConfig(menuJson, callback) { function locateMenuConfig(menuJson, callback) {
if(_.isObject(menuJson[name])) { if(_.has(menuJson, [ 'menus', name ])) {
menuConfig = menuJson[name]; menuConfig = menuJson.menus[name];
callback(null); callback(null);
} else { } else {
callback(new Error('No menu entry for \'' + name + '\'')); callback(new Error('No menu entry for \'' + name + '\''));
@ -66,7 +66,7 @@ function getMenuConfig(name, cb) {
}, },
function locatePromptConfig(promptJson, callback) { function locatePromptConfig(promptJson, callback) {
if(promptJson) { if(promptJson) {
if(_.isObject(promptJson[menuConfig.prompt])) { if(_.has(promptJson, [ 'prompts', menuConfig.prompt ])) {
menuConfig.promptConfig = promptJson[menuConfig.prompt]; menuConfig.promptConfig = promptJson[menuConfig.prompt];
} else { } else {
callback(new Error('No prompt entry for \'' + menuConfig.prompt + '\'')); callback(new Error('No prompt entry for \'' + menuConfig.prompt + '\''));

View File

@ -538,7 +538,7 @@ TelnetClient.prototype.setTermType = function(ttype) {
this.term.env['TERM'] = ttype; this.term.env['TERM'] = ttype;
this.term.termType = ttype; this.term.termType = ttype;
Log.debug({ termType : ttype }, 'Set terminal type'); Log.debug( { termType : ttype }, 'Set terminal type');
} }
TelnetClient.prototype.handleSbCommand = function(evt) { TelnetClient.prototype.handleSbCommand = function(evt) {
@ -571,10 +571,10 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
self.setTermType(evt.envVars[name]); self.setTermType(evt.envVars[name]);
} else if('COLUMNS' === name && 0 === self.term.termWidth) { } else if('COLUMNS' === name && 0 === self.term.termWidth) {
self.term.termWidth = parseInt(evt.envVars[name]); self.term.termWidth = parseInt(evt.envVars[name]);
Log.debug({ termWidth : self.term.termWidth, updateSource : 'NEW-ENVIRON'}, 'Window width updated'); Log.debug({ termWidth : self.term.termWidth, source : 'NEW-ENVIRON'}, 'Window width updated');
} else if('ROWS' === name && 0 === self.term.termHeight) { } else if('ROWS' === name && 0 === self.term.termHeight) {
self.term.termHeight = parseInt(evt.envVars[name]); self.term.termHeight = parseInt(evt.envVars[name]);
Log.debug({ termHeight : self.term.termHeight, updateSource : 'NEW-ENVIRON'}, 'Window height updated'); Log.debug({ termHeight : self.term.termHeight, source : 'NEW-ENVIRON'}, 'Window height updated');
} else { } else {
if(name in self.term.env) { if(name in self.term.env) {
assert(evt.type === SB_COMMANDS.INFO); assert(evt.type === SB_COMMANDS.INFO);
@ -604,7 +604,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
self.term.env['ROWS'] = evt.height; self.term.env['ROWS'] = evt.height;
} }
Log.debug({ termWidth : evt.width , termHeight : evt.height, updateSource : 'NAWS' }, 'Window size updated'); Log.debug({ termWidth : evt.width , termHeight : evt.height, source : 'NAWS' }, 'Window size updated');
} else { } else {
console.log('unhandled SB: ' + JSON.stringify(evt)); console.log('unhandled SB: ' + JSON.stringify(evt));
} }

View File

@ -194,16 +194,18 @@ function ViewController(options) {
setViewProp('maxLength'); setViewProp('maxLength');
//
['styleSGR1', 'styleSGR2'].forEach(function styleSgr(style) { // styleSGRx: 1..25
setViewProp(style, function(v) { //
for(var i = 1; i <= 25; i++) {
setViewProp('styleSGR' + i, function(v) {
if(_.isObject(v)) { if(_.isObject(v)) {
view[style] = ansi.getSGRFromGraphicRendition(v, true); view['styleSGR' + i] = ansi.getSGRFromGraphicRendition(v, true);
} else if(_.isString(v)) { } else if(_.isString(v)) {
view[style] = ansi.fromPipeCode(v); view['styleSGR' + i] = ansi.fromPipeCode(v);
} }
}); });
}); }
setViewProp('fillChar', function(v) { setViewProp('fillChar', function(v) {
if(_.isNumber(v)) { if(_.isNumber(v)) {

View File

@ -33,394 +33,397 @@
} }
} }
*/ */
"connected" : { "menus" : {
"art" : "CONNECT", "art" : "CONNECT",
"next" : "matrix", "connected" : {
"options" : { "next" : "matrix",
"cls" : true, "options" : {
"nextTimeout" : 1500 "cls" : true,
} "nextTimeout" : 1500
}, }
"matrix" : { },
"art" : "matrix", "matrix" : {
"form" : { "art" : "matrix",
"0" : { // :TODO: Make form "0" the default if missing (e.g. optional)... not sure how with current structure though "form" : {
"VM1" : { "0" : { // :TODO: Make form "0" the default if missing (e.g. optional)... not sure how with current structure though
"mci" : { "VM1" : {
"VM1" : { "mci" : {
"submit" : true, "VM1" : {
"focus" : true, "submit" : true,
// :TODO: need a good way to localize these ... Standard Orig->Lookup seems good. "focus" : true,
"items" : [ "Login", "Apply", "Log Off" ]//, // :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:apply"
},
{
"value" : { "1" : 2 },
"action" : "@menu:logoff"
} }
] },
"submit" : {
"*" : [
{
"value" : { "1" : 0 },
"action" : "@menu:login"
},
{
"value" : { "1" : 1 },
"action" : "@menu:apply"
},
{
"value" : { "1" : 2 },
"action" : "@menu:logoff"
}
]
}
}
}
},
"options" : {
"cls" : true
}
},
"login" : {
// :TODO: may want { "prompt" : { "name" : "blah", "action" : ... }}
"prompt" : "userCredentials",
"fallback" : "matrix",
"next" : "newUserActive",
"action" : "@systemMethod:login",
// :TODO: support alt submit method for prompts
// if present, standard filters apply. No need for multiple submit ID's
// since a prompt can only utilize one:
"submit" : [
{
"value" : { "1" : "thing" },
"action" : "@method:doThings"
}
],
"options" : {
"cls" : true
}
},
"logoff" : {
"art" : "LOGOFF",
//"module" : "logoff",
"action" : "@systemMethod:logoff",
"options" : { "cls" : true }
},
"apply" : {
"art" : "APPLY",
"next" : "newUserActive",
"form" : {
"0" : {
"BT12BT13ET1ET10ET2ET3ET4ET5ET6ET7ET8ET9TL11" : {
"mci" : {
"ET1" : {
"focus" : true,
"argName" : "username",
"maxLength" : "@config:users.usernameMax"
},
"ET2" : {
"argName" : "realName",
"maxLength" : 32
},
"ET3" : {
"argName" : "age",
"width" : 3,
"maxLength" : 3
},
"ET4" : {
"argName" : "sex",
"width" : 1,
"maxLength" : 1
},
"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"
},
"BT12" : {
"submit" : true,
"text" : "Apply"
},
"BT13" : {
"submit" : [ "esc" ],
"text" : "Cancel"
}
},
"submit" : {
"12" : [ // Apply
{
"value" : 12, // :TODO: better, this should be optional; if not present it's a any match
"action" : "@method:apply/submitApplication",
"extraArgs" : {
"inactive" : "userNeedsActivated",
"error" : "newUserCreateError"
}
}
],
"13" : [ // Cancel
{
"value" : 13,
"action" : "@menu:matrix"
}
]
}
}
}
},
"options" : {
"cls" : true
}
},
"newUserActive" : {
"art" : "userstats",
//"prompt" : "pause",
"options" : {
// :TODO: implement MCI codes for this
"cls" : true
}
},
"demoMain" : {
"art" : "demo_selection_vm.ans",
"options" : { "cls" : true },
"form" : {
"0" : {
"VM1" : {
"mci" : {
"VM1" : {
"items" : [
"Single Line Text Editing Views",
"Spinner & Toggle Views",
"Mask Edit Views",
"Vertical Menu Views",
"Horizontal Menu Views",
"Art Display",
"Some More Stuff",
"Other"
],
"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" : 5 },
"action" : "@menu:demoArtDisplay"
}
]
}
} }
} }
} }
}, },
"options" : { "demoEditTextView" : {
"cls" : true "art" : "demo_edit_text_view1.ans",
} "options" : { "cls" : true },
}, "form" : {
"login" : { "0" : {
// :TODO: may want { "prompt" : { "name" : "blah", "action" : ... }} "BT5ET1ET2ET3ET4" : {
"prompt" : "userCredentials", "mci" : {
"fallback" : "matrix", "ET1" : {
"next" : "newUserActive", "width" : 20,
"action" : "@systemMethod:login", "maxLength" : 20
},
// :TODO: support alt submit method for prompts "ET2" : {
// if present, standard filters apply. No need for multiple submit ID's "width" : 20,
// since a prompt can only utilize one: "maxLength" : 40,
"submit" : [ "textOverflow" : "..."
{ },
"value" : { "1" : "thing" }, "ET3" : {
"action" : "@method:doThings" "width" : 20,
} "fillChar" : "-",
], "styleSGR1" : "|00|36",
"maxLength" : 20
"options" : { },
"cls" : true "ET4" : {
} "width" : 20,
}, "maxLength" : 20,
"logoff" : { "password" : true
"art" : "LOGOFF", },
//"module" : "logoff", "BT5" : {
"action" : "@systemMethod:logoff", "width" : 8,
"options" : { "cls" : true } "text" : "< Back",
}, "submit" : [ "esc" ]
"apply" : { }
"art" : "APPLY",
"next" : "newUserActive",
"form" : {
"0" : {
"BT12BT13ET1ET10ET2ET3ET4ET5ET6ET7ET8ET9TL11" : {
"mci" : {
"ET1" : {
"focus" : true,
"argName" : "username",
"maxLength" : "@config:users.usernameMax"
}, },
"ET2" : { "submit" : {
"argName" : "realName", "*" : [
"maxLength" : 32 {
}, "value" : 5,
"ET3" : { "action" : "@menu:demoMain"
"argName" : "age", }
"width" : 3, ]
"maxLength" : 3
},
"ET4" : {
"argName" : "sex",
"width" : 1,
"maxLength" : 1
},
"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"
},
"BT12" : {
"submit" : true,
"text" : "Apply"
},
"BT13" : {
"submit" : [ "esc" ],
"text" : "Cancel"
} }
},
"submit" : {
"12" : [ // Apply
{
"value" : 12, // :TODO: better, this should be optional; if not present it's a any match
"action" : "@method:apply/submitApplication",
"extraArgs" : {
"inactive" : "userNeedsActivated",
"error" : "newUserCreateError"
}
}
],
"13" : [ // Cancel
{
"value" : 13,
"action" : "@menu:matrix"
}
]
} }
} }
} }
}, },
"options" : { "demoSpinAndToggleView" : {
"cls" : true "art" : "demo_spin_and_toggle.ans",
} "options" : { "cls" : true },
}, "form" : {
"newUserActive" : { "0" : {
"art" : "userstats", "BT8SM1SM2TM3" : {
//"prompt" : "pause", "mci" : {
"options" : { "SM1" : {
// :TODO: implement MCI codes for this "items" : [ "Henry Morgan", "François l'Ollonais", "Roche Braziliano", "Black Bart", "Blackbeard" ]
"cls" : true
}
},
"demoMain" : {
"art" : "demo_selection_vm.ans",
"options" : { "cls" : true },
"form" : {
"0" : {
"VM1" : {
"mci" : {
"VM1" : {
"items" : [
"Single Line Text Editing Views",
"Spinner & Toggle Views",
"Mask Edit Views",
"Vertical Menu Views",
"Horizontal Menu Views",
"Art Display",
"Some More Stuff",
"Other"
],
"height" : 10,
"itemSpacing" : 1,
"justify" : "center",
"focusTextStyle" : "small i"
}
},
"submit" : {
"*" : [
{
"value" : { "1" : 0 },
"action" : "@menu:demoEditTextView"
}, },
{ "SM2" : {
"value" : { "1" : 1 }, "items" : [ "Razor 1911", "DrinkOrDie", "TRSI" ]
"action" : "@menu:demoSpinAndToggleView"
}, },
{ "TM3" : {
"value" : { "1" : 2 }, "items" : [ "Yarly", "Nowaii" ],
"action" : "@menu:demoMaskEditView" "styleSGR1" : "|00|30|01",
"hotkeys" : { "Y" : 0, "N" : 1 }
}, },
{ "BT8" : {
"value" : { "1" : 5 }, "text" : "< Back",
"action" : "@menu:demoArtDisplay" "submit" : [ "esc" ]
} }
] },
"submit" : {
"*" : [
{
"value" : 8,
"action" : "@menu:demoMain"
}
]
}
} }
} }
} }
} },
}, "demoMaskEditView" : {
"demoEditTextView" : { "art" : "demo_mask_edit_text_view1.ans",
"art" : "demo_edit_text_view1.ans", "options" : { "cls" : true },
"options" : { "cls" : true }, "form" : {
"form" : { "0" : {
"0" : { "BT5ME1ME2" : {
"BT5ET1ET2ET3ET4" : { "mci" : {
"mci" : { "ME1" : {
"ET1" : { "maskPattern" : "##/##/##",
"width" : 20, "styleSGR1" : "|00|30|01",
"maxLength" : 20 "styleSGR2" : "|00|45|01"
},
"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" : [ "esc" ]
}
},
"submit" : {
"*" : [
{
"value" : 5,
"action" : "@menu:demoMain"
} }
] }
} }
} }
} }
} },
}, "demoArtDisplay" : {
"demoSpinAndToggleView" : { "art" : "demo_selection_vm.ans",
"art" : "demo_spin_and_toggle.ans", "options" : { "cls" : true },
"options" : { "cls" : true }, "form" : {
"form" : { "0" : {
"0" : { "VM1" : {
"BT8SM1SM2TM3" : { "mci" : {
"mci" : { "VM1" : {
"SM1" : { "items" : [
"items" : [ "Henry Morgan", "François l'Ollonais", "Roche Braziliano", "Black Bart", "Blackbeard" ] "Defaults - DOS ANSI",
}, "Defaults - Amiga",
"SM2" : { "Pause at Term Height"
"items" : [ "Razor 1911", "DrinkOrDie", "TRSI" ] ],
}, // :TODO: justify not working??
"TM3" : { "focusTextStyle" : "small i"
"items" : [ "Yarly", "Nowaii" ],
"styleSGR1" : "|00|30|01",
"hotkeys" : { "Y" : 0, "N" : 1 }
},
"BT8" : {
"text" : "< Back",
"submit" : [ "esc" ]
}
},
"submit" : {
"*" : [
{
"value" : 8,
"action" : "@menu:demoMain"
} }
] },
} "submit" : {
} "*" : [
} {
} "value" : { "1" : 0 },
}, "action" : "@menu:demoDefaultsDosAnsi"
"demoMaskEditView" : { }
"art" : "demo_mask_edit_text_view1.ans", ]
"options" : { "cls" : true },
"form" : {
"0" : {
"BT5ME1ME2" : {
"mci" : {
"ME1" : {
"maskPattern" : "##/##/##",
"styleSGR1" : "|00|30|01"
} }
} }
} }
} }
},
"demoDefaultsDosAnsi" : {
"art" : "WE-CIZB.ANS",
"options" : { "cls" : true }
} }
},
"demoArtDisplay" : { /*
"art" : "demo_selection_vm.ans", :TODO: conceptual simplified menus -- actions/etc. without forms
"options" : { "cls" : true },
"form" : {
"0" : {
"VM1" : {
"mci" : {
"VM1" : {
"items" : [
"Defaults - DOS ANSI",
"Defaults - Amiga",
"Pause at Term Height"
],
// :TODO: justify not working??
"focusTextStyle" : "small i"
}
},
"submit" : {
"*" : [
{
"value" : { "1" : 0 },
"action" : "@menu:demoDefaultsDosAnsi"
}
]
}
}
}
}
},
"demoDefaultsDosAnsi" : {
"art" : "WE-CIZB.ANS",
"options" : { "cls" : true }
}
/*
:TODO: conceptual simplified menus -- actions/etc. without forms
{ {
"myMenu" : { "myMenu" : {
"art" : "MENUART", "art" : "MENUART",
"mci" : { // lack of "form": direct to form:0 {} "mci" : { // lack of "form": direct to form:0 {}
"VM1" : { "VM1" : {
"items" : [ "Hello", "Goodbye" ], "items" : [ "Hello", "Goodbye" ],
"action" : "@method:someMethod" // implies { "submit" : true } "action" : "@method:someMethod" // implies { "submit" : true }
}, },
"submit" : { "submit" : {
// alternate form with filters // alternate form with filters
}
} }
} }
} }
} */
*/ /*
/* "demoEditTextView" : {
"demoEditTextView" : { "art" : "demo_edit_text_view.ans",
"art" : "demo_edit_text_view.ans", "options" : { "cls" : true },
"options" : { "cls" : true }, "form" : {
"form" : { "0" : {
"0" : { "ET1ET2ET3ET5SM4TM6" : {
"ET1ET2ET3ET5SM4TM6" : { "mci" : {
"mci" : { "ET1" : { "maxLength" : 1 },
"ET1" : { "maxLength" : 1 }, "ET2" : { "maxLength" : 1 },
"ET2" : { "maxLength" : 1 }, "ET3" : { "maxLength" : 1 },
"ET3" : { "maxLength" : 1 }, "SM4" : {
"SM4" : { "items" : [ "One", "Two", "Three", "Four" ]
"items" : [ "One", "Two", "Three", "Four" ] },
}, "ET5" : {
"ET5" : { "password" : true,
"password" : true, "submit" : [ "esc" ],
"submit" : [ "esc" ], "fillChar" : "#"
"fillChar" : "#" },
}, "TM6" : {
"TM6" : { "items" : [ "Yes", "No" ],
"items" : [ "Yes", "No" ], "hotkeys" : { "Y" : 0, "n" : 1 }
"hotkeys" : { "Y" : 0, "n" : 1 } }
} }
} }
} }
} }
} }
*/
} }
*/
} }

View File

@ -1,71 +1,72 @@
{ {
"userCredentials" : { "prompts" : {
"art" : "usercred", "art" : "usercred",
"mci" : { "userCredentials" : {
"ET1" : { "mci" : {
"argName" : "username", "ET1" : {
"maxLength" : "@config:users.usernameMax" "argName" : "username",
}, "maxLength" : "@config:users.usernameMax"
"ET2" : { },
"submit" : true, "ET2" : {
"argName" : "password", "submit" : true,
"password" : true, "argName" : "password",
"maxLength" : "@config:users.passwordMax" "password" : true,
"maxLength" : "@config:users.passwordMax"
}
} }
} },
},
"pause" : {
"art" : "pause"
/*
"mci" : {
// :TODO: Need special pause for a key MCI
// e.g. %PA -> themed prompt
}
...or maybe pause should just be special:
{
...
"pause" true
// uses theme pause which can be art/inline/etc.
}
... better, a special prompt
GetKeyView
* showKey : false
*/
},
"standard" : {
"pause" : { "pause" : {
"art" : "pause" "art" : "pause"
/*
"mci" : {
// :TODO: Need special pause for a key MCI
// e.g. %PA -> themed prompt
}
...or maybe pause should just be special:
{
...
"pause" true
// uses theme pause which can be art/inline/etc.
}
... better, a special prompt
GetKeyView
* echoKey : false
*/
},
"standard" : {
"pause" : {
"art" : "pause"
}
},
"custom" : {
} }
}, /*
"custom" : { see notes in menu_module.js also
...how to allow for this to come from the theme first???
same as custom vc drawing/etc.? ...
} {
/* "theme" : {
see notes in menu_module.js also "inlineArt" : {
...how to allow for this to come from the theme first??? "something" : "%MC and |01Pipe codes here"
same as custom vc drawing/etc.? ... }
{
"theme" : {
"inlineArt" : {
"something" : "%MC and |01Pipe codes here"
} }
} }
}
"pause" : { "pause" : {
"art" : "@inline:simplePrompt", "art" : "@inline:simplePrompt",
// support pipe codes & MCI // support pipe codes & MCI
"simplePrompt" : "--------/ Pause /----------------", "simplePrompt" : "--------/ Pause /----------------",
"mci" : { "mci" : {
}
} }
*/
} }
*/
} }