* Trailing LF handling is now 'trailingLF' option, with 'default', 'yes', 'no', etc.

* Initial checking of WIP Mystery Skulls theme by Luciano Ayres of blocktronics
* Fix random theme selection
* WIP on theme customization apply: Needs to be much more flexible than current
* MenuModule will use .next > .fallback > default fallback
This commit is contained in:
Bryan Ashby
2015-09-27 15:35:24 -06:00
parent 68b8af7975
commit 05812f57f0
25 changed files with 187 additions and 105 deletions
+23 -5
View File
@@ -36,15 +36,14 @@ function ANSIEscapeParser(options) {
mciReplaceChar : '', mciReplaceChar : '',
termHeight : 25, termHeight : 25,
termWidth : 80, termWidth : 80,
omitTrailingLF : false, trailingLF : 'default', // default|omit|no|yes, ...
}); });
this.mciReplaceChar = miscUtil.valueWithDefault(options.mciReplaceChar, ''); this.mciReplaceChar = miscUtil.valueWithDefault(options.mciReplaceChar, '');
this.termHeight = miscUtil.valueWithDefault(options.termHeight, 25); this.termHeight = miscUtil.valueWithDefault(options.termHeight, 25);
this.termWidth = miscUtil.valueWithDefault(options.termWidth, 80); this.termWidth = miscUtil.valueWithDefault(options.termWidth, 80);
this.omitTrailingLF = miscUtil.valueWithDefault(options.omitTrailingLF, false); this.trailingLF = miscUtil.valueWithDefault(options.trailingLF, 'default');
function getArgArray(array) { function getArgArray(array) {
var i = array.length; var i = array.length;
while(i--) { while(i--) {
@@ -246,9 +245,28 @@ function ANSIEscapeParser(options) {
if(pos < buffer.length) { if(pos < buffer.length) {
var lastBit = buffer.slice(pos); var lastBit = buffer.slice(pos);
if(self.omitTrailingLF && '\r\n' === lastBit.slice(-2).toString()) {
lastBit = lastBit.slice(pos, -2); // trim off last CRLF // :TODO: check for various ending LF's, not just DOS \r\n
if('\r\n' === lastBit.slice(-2).toString()) {
switch(self.trailingLF) {
case 'default' :
//
// Default is to *not* omit the trailing LF
// if we're going to end on termHeight
//
if(this.termHeight === self.row) {
lastBit = lastBit.slice(0, -2);
}
break;
case 'omit' :
case 'no' :
case false :
lastBit = lastBit.slice(0, -2);
break;
}
} }
parseMCI(lastBit) parseMCI(lastBit)
} }
+1 -1
View File
@@ -417,7 +417,7 @@ function display(options, cb) {
mciReplaceChar : mciReplaceChar, mciReplaceChar : mciReplaceChar,
termHeight : options.client.term.termHeight, termHeight : options.client.term.termHeight,
termWidth : options.client.term.termWidth, termWidth : options.client.term.termWidth,
omitTrailingLF : options.omitTrailingLF, trailingLF : options.trailingLF,
}); });
var mciMap = {}; var mciMap = {};
+8 -8
View File
@@ -238,18 +238,18 @@ function startListening() {
} }
function prepareClient(client, cb) { function prepareClient(client, cb) {
var theme = require('./theme.js');
// :TODO: it feels like this should go somewhere else... and be a bit more elegant. // :TODO: it feels like this should go somewhere else... and be a bit more elegant.
if('*' === conf.config.preLoginTheme) { if('*' === conf.config.preLoginTheme) {
var theme = require('./theme.js');
client.user.properties.theme_id = theme.getRandomTheme() || ''; client.user.properties.theme_id = theme.getRandomTheme() || '';
theme.loadTheme(client.user.properties.theme_id, function themeLoaded(err, theme) {
client.currentTheme = theme;
cb(null);
});
} else { } else {
client.user.properties.theme_id = conf.config.preLoginTheme; client.user.properties.theme_id = conf.config.preLoginTheme;
cb(null);
} }
theme.loadTheme(client.user.properties.theme_id, function themeLoaded(err, theme) {
client.currentTheme = theme;
cb(null);
});
} }
+17 -8
View File
@@ -11,6 +11,7 @@ var events = require('events');
var util = require('util'); var util = require('util');
var assert = require('assert'); var assert = require('assert');
var hjson = require('hjson'); var hjson = require('hjson');
var _ = require('lodash');
function ConfigCache() { function ConfigCache() {
events.EventEmitter.call(this); events.EventEmitter.call(this);
@@ -54,21 +55,29 @@ function ConfigCache() {
util.inherits(ConfigCache, events.EventEmitter); util.inherits(ConfigCache, events.EventEmitter);
ConfigCache.prototype.getConfig = function(filePath, cb) { ConfigCache.prototype.getConfigWithOptions = function(options, cb) {
var self = this; assert(_.isString(options.filePath));
if(filePath in this.cache) { var self = this;
cb(null, this.cache[filePath], false); var isCached = (options.filePath in this.cache);
} else {
this.reCacheConfigFromFile(filePath, function fileCached(err, config) { if(options.forceReCache || !isCached) {
if(!err) { this.reCacheConfigFromFile(options.filePath, function fileCached(err, config) {
self.gaze.add(filePath); if(!err && !isCached) {
self.gaze.add(options.filePath);
} }
cb(err, config, true); cb(err, config, true);
}); });
} else {
cb(null, this.cache[options.filePath], false);
} }
}; };
ConfigCache.prototype.getConfig = function(filePath, cb) {
this.getConfigWithOptions( { filePath : filePath }, cb);
};
ConfigCache.prototype.getModConfig = function(fileName, cb) { ConfigCache.prototype.getModConfig = function(fileName, cb) {
this.getConfig(paths.join(Config.paths.mods, fileName), cb); this.getConfig(paths.join(Config.paths.mods, fileName), cb);
}; };
+4 -3
View File
@@ -378,9 +378,10 @@ function FullScreenEditorModule(options) {
self.client, self.client,
{ font : self.menuConfig.font }, { font : self.menuConfig.font },
function displayed(err, artData) { function displayed(err, artData) {
mciData[n] = artData; if(artData) {
mciData[n] = artData;
self[n] = { height : artData.height }; self[n] = { height : artData.height };
}
next(err); next(err);
} }
+20 -20
View File
@@ -48,10 +48,10 @@ function MenuModule(options) {
theme.displayThemedAsset( theme.displayThemedAsset(
self.menuConfig.art, self.menuConfig.art,
self.client, self.client,
{ font : self.menuConfig.font }, self.menuConfig.options, // can include .font, .trailingLF, etc.
function displayed(err, artData) { function displayed(err, artData) {
if(err) { if(err) {
self.client.log.debug( { art : self.menuConfig.arg, err : err }, 'Could not display art'); self.client.log.debug( { art : self.menuConfig.art, err : err }, 'Could not display art');
} else { } else {
mciData.menu = artData.mciMap; mciData.menu = artData.mciMap;
} }
@@ -83,7 +83,7 @@ function MenuModule(options) {
theme.displayThemedAsset( theme.displayThemedAsset(
promptConfig.art, promptConfig.art,
self.client, self.client,
{ font : self.menuConfig.font }, self.menuConfig.options, // can include .font, .trailingLF, etc.
function displayed(err, artData) { function displayed(err, artData) {
if(!err) { if(!err) {
mciData.prompt = artData.mciMap; mciData.prompt = artData.mciMap;
@@ -130,7 +130,6 @@ function MenuModule(options) {
self.finishedLoading(); self.finishedLoading();
self.nextMenu(); self.nextMenu();
//self.nextAction();
} }
); );
}; };
@@ -143,20 +142,22 @@ function MenuModule(options) {
return _.isNumber(self.menuConfig.options.nextTimeout); return _.isNumber(self.menuConfig.options.nextTimeout);
}; };
// :TODO: Convert this to process "next" instead of "action"
this.nextAction = function() {
if(!_.isObject(self.menuConfig.form) && !_.isString(self.menuConfig.prompt) &&
_.isString(self.menuConfig.action))
{
menuUtil.handleAction(self.client, null, self.menuConfig);
}
};
this.nextMenu = function() { this.nextMenu = function() {
if(!_.isObject(self.menuConfig.form) && !_.isString(self.menuConfig.prompt) && function goNext() {
!_.isUndefined(self.menuConfig.next)) if(_.isString(self.menuConfig.next)) {
{ menuUtil.handleNext(self.client, self.menuConfig.next);
} else {
self.client.fallbackMenuModule( { }, function fallback(err) {
// :TODO: this seems sloppy... look into further
});
}
}
if(!_.isObject(self.menuConfig.form) && !_.isString(self.menuConfig.prompt)) {
/* /*
If 'next' is supplied, we'll use it. Otherwise, utlize fallback which
may be explicit (supplied) or non-explicit (previous menu)
'next' may be a simple asset, or a object with next.asset and 'next' may be a simple asset, or a object with next.asset and
extrArgs extrArgs
@@ -168,14 +169,13 @@ function MenuModule(options) {
asset: assetSpec asset: assetSpec
extraArgs: ... extraArgs: ...
} }
*/ */
if(self.hasNextTimeout()) { if(self.hasNextTimeout()) {
setTimeout(function nextTimeout() { setTimeout(function nextTimeout() {
menuUtil.handleNext(self.client, self.menuConfig.next); goNext();
}, this.menuConfig.options.nextTimeout); }, this.menuConfig.options.nextTimeout);
} else { } else {
menuUtil.handleNext(self.client, self.menuConfig.next); goNext();
} }
} }
}; };
+3 -2
View File
@@ -22,7 +22,8 @@ function login(callingMenu, formData, extraArgs) {
// :TODO: if username exists, record failed login attempt to properties // :TODO: if username exists, record failed login attempt to properties
// :TODO: check Config max failed logon attempts/etc. // :TODO: check Config max failed logon attempts/etc.
client.gotoMenuModule( { name : callingMenu.menuConfig.fallback } ); client.fallbackMenuModule();
//client.gotoMenuModule( { name : callingMenu.menuConfig.fallback } );
} else { } else {
var now = new Date(); var now = new Date();
var user = callingMenu.client.user; var user = callingMenu.client.user;
@@ -47,7 +48,7 @@ function login(callingMenu, formData, extraArgs) {
'Already logged in' 'Already logged in'
); );
// :TODO: display custom message if present // :TODO: display custom message if present (Obv/2: TOONODE.ANS)
client.term.write('\nA user by that name is already logged in.\n'); client.term.write('\nA user by that name is already logged in.\n');
+6 -4
View File
@@ -79,7 +79,7 @@ function loadTheme(themeID, cb) {
var path = paths.join(Config.paths.themes, themeID, 'theme.hjson'); var path = paths.join(Config.paths.themes, themeID, 'theme.hjson');
configCache.getConfig(path, function loaded(err, theme) { configCache.getConfigWithOptions( { filePath : path, forceReCache : true }, function loaded(err, theme) {
if(err) { if(err) {
cb(err); cb(err);
} else { } else {
@@ -195,12 +195,13 @@ function displayThemeArt(options, cb) {
if(err) { if(err) {
cb(err); cb(err);
} else { } else {
// :TODO: just use simple merge of options -> displayOptions
var dispOptions = { var dispOptions = {
art : artInfo.data, art : artInfo.data,
sauce : artInfo.sauce, sauce : artInfo.sauce,
client : options.client, client : options.client,
font : options.font, font : options.font,
omitTrailingLF : options.omitTrailingLF, trailingLF : options.trailingLF,
}; };
art.display(dispOptions, function displayed(err, mciMap, extraInfo) { art.display(dispOptions, function displayed(err, mciMap, extraInfo) {
@@ -250,7 +251,7 @@ function displayThemedPause(options, cb) {
displayThemedAsset( displayThemedAsset(
promptConfig.art, promptConfig.art,
options.client, options.client,
{ font : promptConfig.font, omitTrailingLF : true }, promptConfig.options,
function displayed(err, artData) { function displayed(err, artData) {
artInfo = artData; artInfo = artData;
callback(err); callback(err);
@@ -323,11 +324,12 @@ function displayThemedAsset(assetSpec, client, options, cb) {
return; return;
} }
// :TODO: just use simple merge of options -> displayOptions
var dispOpts = { var dispOpts = {
name : artAsset.asset, name : artAsset.asset,
client : client, client : client,
font : options.font, font : options.font,
omitTrailingLF : options.omitTrailingLF, trailingLF : options.trailingLF,
}; };
switch(artAsset.type) { switch(artAsset.type) {
+3 -3
View File
@@ -571,15 +571,15 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) {
}); });
}, },
function applyThemeCustomization(callback) { function applyThemeCustomization(callback) {
if(_.isObject(formConfig)) { //if(_.isObject(formConfig)) {
menuUtil.applyThemeCustomization({ menuUtil.applyThemeCustomization({
name : self.client.currentMenuModule.menuName, name : self.client.currentMenuModule.menuName,
type : 'menus', type : 'menus',
client : self.client, client : self.client,
configMci : formConfig.mci, configMci : formConfig ? formConfig.mci : {},
formId : formIdKey, formId : formIdKey,
}); });
} //}
callback(null); callback(null);
}, },
Binary file not shown.
Binary file not shown.
Binary file not shown.
+51 -49
View File
@@ -61,6 +61,9 @@
matrix: { matrix: {
art: matrix art: matrix
options: {
}
form: { form: {
0: { // :TODO: Make form "0" the default if missing (e.g. optional)... not sure how with current structure though 0: { // :TODO: Make form "0" the default if missing (e.g. optional)... not sure how with current structure though
VM: { VM: {
@@ -69,7 +72,7 @@
submit: true submit: true
focus: true focus: true
// :TODO: need a good way to localize these ... Standard Orig->Lookup seems good. // :TODO: need a good way to localize these ... Standard Orig->Lookup seems good.
items: [ "Login", "Apply", "Log Off" ] items: [ "login", "apply", "log off" ]
} }
} }
@@ -111,45 +114,45 @@
} }
]*/ ]*/
}, },
"login2" : {
"art" : "USRCRED", login2: {
"fallback" : "matrix", art: USERLOG
next: messageArea next: messageArea
//"next" : "fullLoginSequenceLoginArt", //"next" : "fullLoginSequenceLoginArt",
"form" : { form: {
"0" : { 0: {
"mci" : { mci: {
"ET1" : { ET1: {
"width" : 20, maxLength: @config:users.usernameMax
"maxLength" : "@config:users.usernameMax", argName: username
"argName" : "username", focus: true
"focus" : true
},
"ET2" : {
"width" : 20,
"password" : true,
"maxLength" : "@config:users.passwordMax",
"argName" : "password",
"submit" : true
} }
}, ET2: {
"submit" : { password: true
"*" : [ maxLength: @config:users.passwordMax
argName: password
submit: true
}
}
submit: {
*: [
{ {
"value" : { "password" : null }, value: { password: null }
"action" : "@systemMethod:login" action: @systemMethod:login
} }
] ]
}, }
"actionKeys" : [ actionKeys: [
{ {
"keys" : [ "escape" ], keys: [ "escape" ]
"action" : "@menu:matrix" action: @menu:matrix
} }
] ]
} }
} }
}, }
"logoff" : { "logoff" : {
"art" : "LOGOFF", "art" : "LOGOFF",
"next" : "@systemMethod:logoff", "next" : "@systemMethod:logoff",
@@ -390,7 +393,7 @@
"next" : "fullLoginSequenceUserStats" "next" : "fullLoginSequenceUserStats"
}, },
"fullLoginSequenceUserStats" : { "fullLoginSequenceUserStats" : {
"art" : "USRSTAT", art: STATUS
"options" : { "pause" : true }, "options" : { "pause" : true },
"next" : "mainMenu" "next" : "mainMenu"
}, },
@@ -404,17 +407,20 @@
"options" : { "pause" : true } "options" : { "pause" : true }
//"action" : "@menu:lastCallers" //"action" : "@menu:lastCallers"
}, },
"mainMenu" : { mainMenu: {
"art" : "MMENU1", art: MMENU
"desc" : "Main Menu", /*options: {
"prompt" : "menuCommand", trailingLF: yes
}*/
desc: Main Menu
prompt: menuCommand
"submit" : [ "submit" : [
{ {
"value" : { "command" : "G" }, "value" : { "command" : "G" },
"action" : "@menu:logoff" "action" : "@menu:logoff"
}, },
{ {
"value" : { "command" : "D" }, "value" : { "command" : "O" },
"action" : "@menu:doorPimpWars" "action" : "@menu:doorPimpWars"
}, },
/* /*
@@ -441,20 +447,16 @@
} }
] ]
}, },
"mainMenuLastCallers" : { mainMenuLastCallers: {
"module" : "last_callers", module: last_callers
"art" : "LASTCALL", art: LASTCALL
"options" : { "pause" : true }, options: { pause: true }
"config" : { }
"dateTimeFormat" : "ddd MMM Do h:mm a" mainMenuUserStats: {
}, art: STATUS
"next" : "mainMenu" options: { pause: true }
}, next: mainMenu
"mainMenuUserStats" : { }
"art" : "USRSTAT",
"options" : { "pause" : true },
"next" : "mainMenu"
},
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// Message Area Related // Message Area Related
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
+5 -2
View File
@@ -59,11 +59,14 @@
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// Standard / Required // Standard / Required
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
"pause" : { pause: {
// //
// Any menu 'pause' will use this prompt // Any menu 'pause' will use this prompt
// //
"art" : "pause" art: pause
options: {
trailingLF: no
}
/* /*
"mci" : { "mci" : {
// :TODO: Need special pause for a key MCI // :TODO: Need special pause for a key MCI
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,46 @@
{
info: {
name: Mystery Skull
author: Luciano Ayres
group: blocktronics
}
customization: {
defaults: {
general: {
passwordChar: *
}
dateTimeFormat: {
short: MMM Do h:mm a
}
}
menus: {
matrix: {
VM1: {
focusTextStyle: first lower
}
}
login2: {
ET1: { width: 14 }
ET2: { width: 14 }
}
mainMenuUserStats: {
UN1: { width: 17 }
UR2: { width: 17 }
LO3: { width: 17 }
UF4: { width: 17 }
UG5: { width: 17 }
UT6: { width: 17 }
UC7: { width: 17 }
}
mainMenuLastCallers: {
}
}
}
}