diff --git a/core/ansi_term.js b/core/ansi_term.js index d69cf1e1..671f041c 100644 --- a/core/ansi_term.js +++ b/core/ansi_term.js @@ -14,6 +14,8 @@ var assert = require('assert'); var binary = require('binary'); var miscUtil = require('./misc_util.js'); +exports.getFGColorValue = getFGColorValue; +exports.getBGColorValue = getBGColorValue; exports.sgr = sgr; exports.clearScreen = clearScreen; exports.resetScreen = resetScreen; @@ -69,7 +71,7 @@ var CONTROL = { // Select Graphics Rendition // See http://cvs.synchro.net/cgi-bin/viewcvs.cgi/*checkout*/src/conio/cterm.txt // -var SGR = { +var SGRValues = { reset : 0, bold : 1, dim : 2, @@ -96,11 +98,21 @@ var SGR = { greenBG : 42, yellowBG : 43, blueBG : 44, - magentaBG : 45, + cyanBG : 47, whiteBG : 47, }; +function getFGColorValue(name) { + return SGRValues[name]; +} + +function getBGColorValue(name) { + return SGRValues[name + 'BG']; +} + + + // See http://cvs.synchro.net/cgi-bin/viewcvs.cgi/*checkout*/src/conio/cterm.txt // :TODO: document var SYNC_TERM_FONTS = [ @@ -162,8 +174,8 @@ Object.keys(CONTROL).forEach(function onControlName(name) { }); // Create various color methods such as white(), yellowBG(), reset(), ... -Object.keys(SGR).forEach(function onSgrName(name) { - var code = SGR[name]; +Object.keys(SGRValues).forEach(function onSgrName(name) { + var code = SGRValues[name]; exports[name] = function() { return ESC_CSI + code + 'm'; @@ -173,7 +185,7 @@ Object.keys(SGR).forEach(function onSgrName(name) { function sgr() { // // - Allow an single array or variable number of arguments - // - Each element can be either a integer or string found in SGR + // - Each element can be either a integer or string found in SGRValues // which in turn maps to a integer // if(arguments.length <= 0) { @@ -187,11 +199,11 @@ function sgr() { var args = Array.isArray(arguments[0]) ? arguments[0] : arguments; for(var i = 0; i < args.length; i++) { if(typeof args[i] === 'string') { - if(args[i] in SGR) { + if(args[i] in SGRValues) { if(result.length > 0) { result += ';'; } - result += SGR[args[i]]; + result += SGRValues[args[i]]; } } else if(typeof args[i] === 'number') { if(result.length > 0) { diff --git a/core/view.js b/core/view.js index 71d9c556..d4d5c7bc 100644 --- a/core/view.js +++ b/core/view.js @@ -13,7 +13,7 @@ exports.VIEW_SPECIAL_KEY_MAP_DEFAULT = VIEW_SPECIAL_KEY_MAP_DEFAULT; var VIEW_SPECIAL_KEY_MAP_DEFAULT = { accept : [ 'enter' ], exit : [ 'esc' ], - backspace : [ 'backspace' ], + backspace : [ 'backspace', 'del' ], del : [ 'del' ], next : [ 'tab' ], up : [ 'up arrow' ], @@ -89,6 +89,10 @@ View.prototype.setId = function(id) { this.id = id; }; +View.prototype.getId = function() { + return this.id; +}; + View.prototype.setPosition = function(pos) { // // We allow [x, y], { x : x, y : y }, or (x, y) @@ -116,18 +120,35 @@ View.prototype.setPosition = function(pos) { 'Y position ' + this.position.y + ' out of terminal range ' + this.client.term.termWidth); }; -View.prototype.setColor = function(fg, bg, flags) { - if(fg) { - this.color.fg = fg; +View.prototype.setColor = function(color, bgColor, flags) { + if(_.isObject(color)) { + assert(_.has(color, 'fg')); + assert(_.has(color, 'bg')); + assert(_.has(color, 'flags')); + + this.color = color; + } else { + if(color) { + this.color.fg = color; + } + + if(bgColor) { + this.color.bg = bgColor; + } + + if(_.isNumber(flags)) { + this.color.flags = flags; + } } - if(bg) { - this.color.bg = bg; + // allow strings such as 'red', 'black', etc. to be passed + if(_.isString(this.color.fg)) { + this.color.fg = ansi.getFGColorValue(this.color.fg); } - if('undefined' !== typeof flags) { - this.color.flags = flags; - } + if(_.isString(this.color.bg)) { + this.color.bg = ansi.getBGColorValue(this.color.bg); + } }; View.prototype.getColor = function() { @@ -147,8 +168,6 @@ View.prototype.setFocus = function(focused) { this.hasFocus = focused; this.client.term.write('show' === this.cursor ? ansi.showCursor() : ansi.hideCursor()); - - this.emit(focused ? 'enter' : 'leave'); }; View.prototype.onKeyPress = function(key, isSpecial) { diff --git a/core/view_controller.js b/core/view_controller.js index 43fe8fd6..d4671bf8 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -15,14 +15,17 @@ var _ = require('lodash'); exports.ViewController = ViewController; -function ViewController(client, formId) { +function ViewController(options) { + assert(_.isObject(options)); + assert(_.isObject(options.client)); + events.EventEmitter.call(this); var self = this; - this.client = client; + this.client = options.client; this.views = {}; // map of ID -> view - this.formId = formId || 0; + this.formId = options.formId || 0; this.onClientKeyPress = function(key, isSpecial) { if(isSpecial) { @@ -95,6 +98,16 @@ function ViewController(client, formId) { self.emit('submit', formData); }; + this.switchFocusEvent = function(event, view) { + if(self.emitSwitchFocus) { + return; + } + + self.emitSwitchFocus = true; + self.emit(event, view); + self.emitSwitchFocus = false; + }; + this.attachClientEvents(); } @@ -146,16 +159,17 @@ ViewController.prototype.getFocusedView = function() { ViewController.prototype.switchFocus = function(id) { if(this.focusedView && this.focusedView.acceptsFocus) { + this.switchFocusEvent('leave', this.focusedView); this.focusedView.setFocus(false); } var view = this.getView(id); if(view && view.acceptsFocus) { + this.switchFocusEvent('enter', view); + this.focusedView = view; this.focusedView.setFocus(true); } - - // :TODO: Probably log here }; ViewController.prototype.nextFocus = function() { @@ -234,7 +248,7 @@ ViewController.prototype.loadFromMCIMapAndConfig = function(options, cb) { if(err) { // :TODO: fix logging of err here: Log.warn( - { err : err, mci : Object.keys(options.mciMap), formIdKey : formIdKey } , + { err : err.toString(), mci : Object.keys(options.mciMap), formIdKey : formIdKey } , 'Unable to load menu configuration'); } diff --git a/mods/apply.js b/mods/apply.js index d834cca5..96c26c47 100644 --- a/mods/apply.js +++ b/mods/apply.js @@ -27,10 +27,8 @@ function ApplyModule(menuConfig) { var self = this; - this.clearForm = function() { - [ 1, 2, ].forEach(function onId(id) { - self.viewController.getView(id).clearText(); - }); + this.menuMethods.submitApplication = function(args) { + console.log('do submit') }; } @@ -49,46 +47,63 @@ ApplyModule.prototype.mciReady = function(mciMap) { var self = this; - self.viewController = self.addViewController(new ViewController(self.client)); + self.viewController = self.addViewController(new ViewController({ client : self.client } )); self.viewController.loadFromMCIMapAndConfig( { mciMap : mciMap, menuConfig : self.menuConfig }, function onViewReady(err) { var usernameView = self.viewController.getView(1); - var userExistsView = self.viewController.getView(10); - usernameView.on('leave', function leave() { + var passwordView = self.viewController.getView(9); + var pwConfirmView = self.viewController.getView(10); + var statusView = self.viewController.getView(11); + + self.viewController.on('leave', function leaveView(view) { + switch(view.getId()) { + case 1 : + user.getUserIdAndName(view.getViewData(), function userIdAndName(err) { + var alreadyExists = !err; + if(alreadyExists) { + statusView.setText('Username unavailable!'); + self.viewController.switchFocus(1); // don't allow to leave + } else { + statusView.setText(''); + self.viewController.switchFocus(2); + } + }); + break; + } + }); +/* + usernameView.on('leave', function leaveUsername() { user.getUserIdAndName(usernameView.getViewData(), function userIdAndName(err) { - if(!err) { - userExistsView.setText('That username already exists!'); + var alreadyExists = !err; + if(alreadyExists) { + statusView.setText('Username unavailable!'); + self.viewController.switchFocus(1); // don't allow to leave } else { - userExistsView.setText(''); + statusView.setText(''); + self.viewController.switchFocus(2); } - //if(11 !== self.viewController.getFocusedView()) { - self.viewController.switchFocus(2); - //} }); }); - var pwView = self.viewController.getView(8); - var pwConfirmView = self.viewController.getView(9); - var pwSecureView = self.viewController.getView(11); - var pwConfirmNoticeView = self.viewController.getView(12); - - // :TODO: show a secure meter here instead - pwView.on('leave', function pwLeave() { - if(pwView.getViewData().length > 3) { - pwSecureView.setColor(32); - pwSecureView.setText('Secure'); + passwordView.on('leave', function leavePw() { + if(passwordView.getViewData().length < 3) { + statusView.setText('Password too short!'); + self.viewController.switchFocus(9); } else { - pwSecureView.setColor(31); - pwSecureView.setText('Insecure!'); + statusView.setText(''); } }); - pwConfirmView.on('leave', function confirmPwLeave() { - if(pwView.getViewData() !== pwConfirmView.getViewData()) { - pwConfirmNoticeView.setText('Passwords must match!'); + pwConfirmView.on('leave', function leavePwConfirm() { + if(passwordView.getViewData() !== pwConfirmView.getViewData()) { + statusView.setText('Passwords must match!'); + self.viewController.switchFocus(9); } else { - pwConfirmNoticeView.setText(''); + statusView.setText(''); } }); +*/ + + }); }; \ No newline at end of file diff --git a/mods/art/themes/NU-MAYA/APPLY1.ANS b/mods/art/themes/NU-MAYA/APPLY1.ANS new file mode 100644 index 00000000..ea1b3e49 Binary files /dev/null and b/mods/art/themes/NU-MAYA/APPLY1.ANS differ diff --git a/mods/art/themes/NU-MAYA/theme_info.json b/mods/art/themes/NU-MAYA/theme_info.json index 75864b1c..e8ae536b 100644 --- a/mods/art/themes/NU-MAYA/theme_info.json +++ b/mods/art/themes/NU-MAYA/theme_info.json @@ -1,4 +1,7 @@ { "name" : "Nu Mayan", - "author" : "NuSkooler" + "author" : "NuSkooler", + "config" : { + "passwordChar" : "*" + } } \ No newline at end of file diff --git a/mods/login.js b/mods/login.js index 4cafbc14..a6c1ff4a 100644 --- a/mods/login.js +++ b/mods/login.js @@ -80,7 +80,7 @@ LoginModule.prototype.mciReady = function(mciMap) { var self = this; - self.viewController = self.addViewController(new ViewController(self.client)); + self.viewController = self.addViewController(new ViewController( { client : self.client } )); self.viewController.loadFromMCIMapAndConfig( { mciMap : mciMap, menuConfig : self.menuConfig }, function onViewReady(err) { }); }; \ No newline at end of file diff --git a/mods/matrix.js b/mods/matrix.js index b1af2804..2fc60df3 100644 --- a/mods/matrix.js +++ b/mods/matrix.js @@ -66,7 +66,7 @@ MatrixModule.prototype.mciReady = function(mciMap) { // 2 - Bye! // //var vc = new ViewController(client); - var vc = self.addViewController(new ViewController(self.client)); + var vc = self.addViewController(new ViewController({ client : self.client } )); vc.on('submit', function onSubmit(form) { console.log(form); diff --git a/mods/menu.json b/mods/menu.json index b161e1e2..554328b0 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -105,17 +105,44 @@ "module" : "apply", "form" : { "0" : { - "BN13BN14ET1ET2ET3ET4ET5ET6ET7ET8ET9TL10TL11TL12" : { + "BN12BN13ET1ET10ET2ET3ET4ET5ET6ET7ET8ET9TL11" : { "mci" : { "ET1" : { "focus" : true }, - "BN13" : { + "BN12" : { + "submit" : true, "text" : "Apply" }, - "BN14" : { + "BN13" : { + "submit" : true, "text" : "Cancel" } + }, + "submit" : { + "12" : [ // Apply + { + "value" : { "12" : null }, + "action" : "@method:submitApplication", + "args" : { + "username" : "{1}", + "realName" : "{2}", + "age" : "{3}", + "sex" : "{4}", + "location" : "{5}", + "affils" : "{6}", + "email" : "{7}", + "web" : "{8}", + "password" : "{9}" + } + } + ], + "13" : [ // Cancel + { + "value" : { "13" : null }, + "action" : "@menu:matrix" + } + ] } } } diff --git a/mods/standard_menu.js b/mods/standard_menu.js index 925fe1e5..bb02f155 100644 --- a/mods/standard_menu.js +++ b/mods/standard_menu.js @@ -34,7 +34,7 @@ StandardMenuModule.prototype.mciReady = function(mciMap) { var self = this; - var vc = self.addViewController(new ViewController(self.client)); + var vc = self.addViewController(new ViewController({ client : self.client } )); vc.loadFromMCIMapAndConfig( { mciMap : mciMap, menuConfig : self.menuConfig }, function onViewReady(err) { if(err) { console.log(err);