* Rewrite of menu.json handling. More flexability

* Wildcards in menu.json
* Basic menu.json submit filtering working
This commit is contained in:
Bryan Ashby 2015-04-01 22:13:29 -06:00
parent 1ae571ee44
commit ae71aa9feb
5 changed files with 124 additions and 87 deletions

View File

@ -227,6 +227,7 @@ Client.prototype.defaultHandlerMissingMod = function(err) {
function handler(err) { function handler(err) {
logger.log.error(err); logger.log.error(err);
self.term.write(ansi.resetScreen());
self.term.write('An unrecoverable error has been encountered!\n'); self.term.write('An unrecoverable error has been encountered!\n');
self.term.write('This has been logged for your SysOp to review.\n'); self.term.write('This has been logged for your SysOp to review.\n');
self.term.write('\nGoodbye!\n'); self.term.write('\nGoodbye!\n');

View File

@ -10,6 +10,7 @@ var fs = require('fs');
var paths = require('path'); var paths = require('path');
var async = require('async'); var async = require('async');
var assert = require('assert'); var assert = require('assert');
var _ = require('lodash');
var stripJsonComments = require('strip-json-comments'); var stripJsonComments = require('strip-json-comments');
@ -32,7 +33,7 @@ function loadMenu(name, client, cb) {
try { try {
var menuJson = JSON.parse(stripJsonComments(data)); var menuJson = JSON.parse(stripJsonComments(data));
if('object' !== typeof menuJson[name] || null === menuJson[name]) { if(!_.isObject(menuJson[name])) {
callback(new Error('No configuration entry for \'' + name + '\'')); callback(new Error('No configuration entry for \'' + name + '\''));
} else { } else {
callback(err, menuJson[name]); callback(err, menuJson[name]);
@ -63,8 +64,36 @@ function loadMenu(name, client, cb) {
); );
} }
function getFormConfig(menuConfig, formId, mciMap, cb) {
assert(_.isObject(menuConfig));
if(!_.isObject(menuConfig.form)) {
cb(new Error('Invalid or missing \'form\' member for menu'));
return;
}
if(!_.isObject(menuConfig.form[formId])) {
cb(new Error('No form found for formId ' + formId));
return;
}
var formForId = menuConfig.form[formId];
var mciReqKey = _.sortBy(Object.keys(mciMap), String).join('');
if(_.isObject(formForId[mciReqKey])) {
cb(null, formForId[mciReqKey]);
return;
}
if(_.has(formForId, 'mci') || _.has(formForId, 'submit')) {
cb(null, formForId);
return;
}
cb(new Error('No matching form configuration found'));
}
/*
function getFormConfig(menuConfig, mciMap, cb) { function getFormConfig(menuConfig, mciMap, cb) {
assert(menuConfig); assert(menuConfig);
@ -101,6 +130,7 @@ function getFormConfig(menuConfig, mciMap, cb) {
} }
); );
} }
*/
/* /*
function getFormConfig(menuConfig, mciMap) { function getFormConfig(menuConfig, mciMap) {

View File

@ -6,6 +6,7 @@ var paths = require('path');
var conf = require('./config.js'); var conf = require('./config.js');
var miscUtil = require('./misc_util.js'); var miscUtil = require('./misc_util.js');
var _ = require('lodash');
// exports // exports
exports.loadModule = loadModule; exports.loadModule = loadModule;
@ -36,7 +37,7 @@ function loadModule(name, category, cb) {
return; return;
} }
if(!mod.getModule || typeof mod.getModule !== 'function') { if(!_.isFunction(mod.getModule)) {
cb(new Error('Invalid or missing missing \'getModule\' method')); cb(new Error('Invalid or missing missing \'getModule\' method'));
return; return;
} }

View File

@ -10,7 +10,7 @@ var events = require('events');
var util = require('util'); var util = require('util');
var assert = require('assert'); var assert = require('assert');
var async = require('async'); var async = require('async');
var ld = require('lodash'); var _ = require('lodash');
exports.ViewController = ViewController; exports.ViewController = ViewController;
@ -209,13 +209,14 @@ ViewController.prototype.loadFromMCIMap = function(mciMap) {
ViewController.prototype.loadFromMCIMapAndConfig = function(options, cb) { ViewController.prototype.loadFromMCIMapAndConfig = function(options, cb) {
assert(options.mciMap); assert(options.mciMap);
var factory = new MCIViewFactory(this.client); var factory = new MCIViewFactory(this.client);
var self = this; var self = this;
var formIdKey = options.formId ? options.formId.toString() : '0';
async.waterfall( async.waterfall(
[ [
function getFormConfig(callback) { function getFormConfig(callback) {
menuUtil.getFormConfig(options.menuConfig, options.mciMap, function onFormConfig(err, formConfig) { menuUtil.getFormConfig(options.menuConfig, formIdKey, options.mciMap, function onFormConfig(err, formConfig) {
if(err) { if(err) {
Log.warn(err, 'Unable to load menu configuration'); Log.warn(err, 'Unable to load menu configuration');
} }
@ -281,26 +282,50 @@ ViewController.prototype.loadFromMCIMapAndConfig = function(options, cb) {
// If we have a 'submit' section, create a submit handler // If we have a 'submit' section, create a submit handler
// and map the various entries to menus/etc. // and map the various entries to menus/etc.
// //
if(formConfig.submit && formConfig.submit.length > 0) { if(_.isObject(formConfig.submit)) {
self.on('submit', function onSubmit(formData) { self.on('submit', function onSubmit(formData) {
Log.debug( { formData : formData }, 'Submit form'); Log.debug( { formData : formData }, 'Submit form');
var submitCompare = function(value, other) { var confForFormId;
console.log(value); if(_.isObject(formConfig.submit[formData.submitId])) {
console.log(other); confForFormId = formConfig.submit[formData.submitId];
return false; } else if(_.isObject(formConfig.submit['*'])) {
}; confForFormId = formConfig.submit['*'];
} else {
// no configuration for this submitId
return;
}
for(var c = 0; c < formConfig.submit.length; ++c) { var formValueCompare = function(formDataValue, formConfigValue) {
//console.log(formConfig.submit[c]); //
// Any key(s) in formConfigValue must:
// 1) be present in formDataValue
// 2) must either:
// a) be set to null (wildcard/any)
// b) have matching values
//
var formConfigValueKeys = Object.keys(formConfigValue);
for(var k = 0; k < formConfigValueKeys.length; ++k) {
var memberKey = formConfigValueKeys[k];
if(ld.isEqual(formData.value, formConfig.submit[c].value)) { // submit data contains config key?
self.client.gotoMenuModule(formConfig.submit[c].menu); if(!_.has(formDataValue, memberKey)) {
break; return false; // not present in what was submitted
}
if(null !== formConfigValue[memberKey] && formConfigValue[memberKey] !== formDataValue[memberKey]) {
return false;
}
} }
var equal = ld.isEqual(formData.value, formConfig.submit[c].value, submitCompare); return true;
// :TODO: Match various wildcards, etc. };
for(var c = 0; c < confForFormId.length; ++c) {
if(_.isEqual(formData.value, confForFormId[c].value, formValueCompare)) {
self.client.gotoMenuModule(confForFormId[c].menu);
break;
}
} }
}); });
} }

View File

@ -5,87 +5,67 @@
"matrix" : { "matrix" : {
"art" : "matrix", "art" : "matrix",
// :TODO: Not currently supporting more than form 0. Should probably do that! // :TODO: Not currently supporting more than form 0. Should probably do that!
"form" : [ "form" : {
{ "0" : {
"mciReq" : [ "VM1" ], "VM1" : {
"mci" : { "mci" : {
"VM1" : { "VM1" : {
"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" ]
} }
},
/*
Some Examples:
VerticalMenu: { id: 0, submitId: 1, value: { '1': 1 } }
Another concept:
"menu" : "@helper.js/logoff" -> calls helper.js::logoff(...)
*/
"submit" : [
{
"value" : { "1" : 0 },
"menu" : "login"
}, },
{ "submit" : {
"value" : { "1" : 1 }, "*" : [
"menu" : "apply" {
}, "value" : { "1" : 0 },
{ "menu" : "login"
"value" : { "1" : 2 }, },
"menu" : "logoff" {
"value" : { "1" : 1 },
"menu" : "apply"
},
{
"value" : { "1" : 2 },
"menu" : "logoff"
}
]
} }
] }
} }
] }
}, },
"login" : { "login" : {
"art" : "login", "art" : "login",
"module" : "login", "module" : "login",
"form" : [ "form" : {
{ "0" : {
"mciReq" : [ "ET1", "ET2", "BN3", "BN4" ], "BN3BN4ET1ET2" :{
"mci" :{ "mci" :{
"ET1" : { "ET1" : {
"focus" : true "focus" : true
},
"BN3" : {
"submit" : true,
"text" : "Login"
},
"BN4" : {
"submit" : true,
"text" : "Cancel"
}
}, },
"BN3" : {
"submit" : true,
"text" : "Login"
},
"BN4" : {
"submit" : true,
"text" : "Cancel"
}
},
/*
"submit" : { "submit" : {
"3" : [ // submitId "3" : [ // Login
{ {
"value" : { "3" : null } "value" : { "3" : null }, // :TODO: allow "value" : null
"menu" : "attempt_login"
} }
] ]
} }
... }
"submit" : {
"*" : [ // submitId = any
{
"value" : { "1" : 1 }
}
]
}
*/
"submit" : [
{
"value" : { "3" : null },
"menu" : "pickles"
}
]
} }
] }
}, },
"logoff" : { "logoff" : {
"art" : "logoff", "art" : "logoff",