diff --git a/core/client.js b/core/client.js index 29965b89..8f53446b 100644 --- a/core/client.js +++ b/core/client.js @@ -39,6 +39,7 @@ var user = require('./user.js'); var moduleUtil = require('./module_util.js'); var menuUtil = require('./menu_util.js'); var Config = require('./config.js').config; +var MenuStack = require('./menu_stack.js'); var stream = require('stream'); var assert = require('assert'); @@ -93,6 +94,7 @@ function Client(input, output) { this.user = new user.User(); this.currentTheme = { info : { name : 'N/A', description : 'None' } }; this.lastKeyPressMs = Date.now(); + this.menuStack = new MenuStack(); Object.defineProperty(this, 'node', { get : function() { @@ -363,7 +365,7 @@ function Client(input, output) { } if(key || ch) { - self.log.trace( { key : key, ch : escape(ch) }, 'User keyboard input'); + self.log.trace( { key : key, ch : escape(ch) }, 'User keyboard input'); // jshint ignore:line self.lastKeyPressMs = Date.now(); diff --git a/core/menu_stack.js b/core/menu_stack.js new file mode 100644 index 00000000..8ea815f6 --- /dev/null +++ b/core/menu_stack.js @@ -0,0 +1,124 @@ +/* jslint node: true */ +'use strict'; + +// ENiGMA½ +var menuUtil = require('./menu_util.js'); + +var _ = require('lodash'); + +/* +MenuStack(client) + stack[] push, pop, ... + + next() + goto(name, options, cb) + prev() + +MenuModule + nextMenu() + gotoMenu(name, options, cb) + prevMenu() +*/ + +module.exports = MenuStack; + +function MenuStack(client) { + this.client = client; + this.stack = []; + + var self = this; + + this.push = function(moduleInfo) { + return self.stack.push(moduleInfo); + }; + + this.pop = function() { + return self.stack.pop(); + }; + + this.top = function() { + return self.stack[self.stack.length - 1]; + }; +} + +MenuStack.prototype.next = function(cb) { + var currentModuleInfo = this.menuStack.top(); + + /* + { + instance : modInst, + menuConfig : {}, + extraArgs : {} + name : 'menuName', + savedState : {} + } + */ + + if(!_.isString(currentModuleInfo.menuConfig.next)) { + this.log.error('No \'next\' member in menu config!'); + return; + } + + if(current.menuConfig.next === currentModuleInfo.name) { + this.log.warn('Menu config \'next\' specifies current menu!'); + return; + } + + this.goto(current.menuConfig.next, { }, cb); +}; + +MenuStack.prototype.prev = function() { + +}; + +MenuStack.prototype.goto = function(name, options, cb) { + var currentModuleInfo = this.menuStack.top(); + + var self = this; + + if(name === currentModuleInfo.name) { + var err = new Error('Already at supplied menu!'); + + self.client.log.warn( { menuName : name, error : err.toString() }, 'Cannot go to menu'); + + if(cb) { + cb(err); // non-fatal + } + return; + } + + var loadOpts = { + name : name, + client : self.client, + extraArgs : options.extraArgs, + }; + + menuUtil.loadMenu(loadOpts, function menuLoaded(err, modInst) { + if(err) { + var errCb = cb || self.defaultHandlerMissingMod(); + errCb(err); + } else { + self.client.detachCurrentMenuModule(); + + self.client.log.debug( { menuName : name }, 'Goto menu module'); + + var modInfo = { + name : name, + instance : modInst, + extraArgs : options.extraArgs, + }; + + self.push(modInfo); + + modInst.enter(self.client); + + if(cb) { + cb(null); + } + } + }); +}; + +MenuStack.prototype.getCurrentModule = function() { + return this.top().instance; +};