diff --git a/core/status_bar_view.js b/core/status_bar_view.js index 903fb5d4..ed47ca7d 100644 --- a/core/status_bar_view.js +++ b/core/status_bar_view.js @@ -40,5 +40,25 @@ StatusBarView.prototype.setPanels = function(panels) { |---------------------------------------------| | stuff | */ + assert(_.isArray(panels)); + + this.panels = []; + + var tvOpts = { + cursor : 'hide', + position : { row : this.position.row, col : 0 }, + }; + + panels.forEach(function panel(p) { + assert(_.isObject(p)); + assert(_.has(p, 'width')); + + if(p.text) { + this.panels.push( new TextView( { })) + } else { + this.panels.push( { width : p.width } ); + } + }); + }; diff --git a/core/view_controller.js b/core/view_controller.js index 2a61b6e2..e6d24305 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -74,46 +74,7 @@ function ViewController(options) { }; this.submitForm = function() { - /* - Generate a form resonse. Example: - - { - id : 0, - submitId : 1, - value : { - "1" : "hurp", - "2" : [ 'a', 'b', ... ], - "3" 2, - "pants" : "no way" - } - - } - */ - var formData = { - id : self.formId, - submitId : self.focusedView.id, - value : {}, - }; - - var viewData; - var view; - for(var id in self.views) { - try { - view = self.views[id]; - viewData = view.getData(); - if(!_.isUndefined(viewData)) { - if(_.isString(view.submitArgName)) { - formData.value[view.submitArgName] = viewData; - } else { - formData.value[id] = viewData; - } - } - } catch(e) { - Log.error(e); // :TODO: Log better ;) - } - } - - self.emit('submit', formData); + self.emit('submit', this.getFormData()); }; this.getLogFriendlyFormData = function(formData) { @@ -159,9 +120,6 @@ function ViewController(options) { // :TODO: move this elsewhere this.setViewPropertiesFromMCIConf = function(view, conf) { - // :TODO: This broke at least VerticalMenuView due to order of setting properties... really, - // shouldn't matter what the order is, so that should be fixed. - for(var propName in conf) { var propValue; var propAsset = asset.getViewPropertyAsset(conf[propName]); @@ -176,8 +134,6 @@ function ViewController(options) { default : propValue = propValue = conf[propName]; break; - - } } else { propValue = conf[propName]; @@ -186,141 +142,7 @@ function ViewController(options) { if(!_.isUndefined(propValue)) { view.setPropertyValue(propName, propValue); } - } - - // :TODO: Experimental.... - /* - function setViewProperty2(propName) { - if(!_.isUndefined(conf[propName])) { - var propValue; - var propAsset = asset.getViewPropertyAsset(conf[propName]); - if(propAsset) { - switch(propAsset.type) { - case 'config' : - propValue = asset.resolveConfigAsset(config[propName]); - break; - - // :TODO: handle @art (e.g. text : @art ...) - - default : - propValue = propValue = conf[propName]; - break; - - - } - } else { - propValue = conf[propName]; - } - - if(!_.isUndefined(propValue)) { - view.setPropertyValue(propName, propValue); - } - } - } - - function setViewProp(propName, setter) { - if(!_.isUndefined(conf[propName])) { - var propValue; - var propAsset = asset.getViewPropertyAsset(conf[propName]); - if(propAsset) { - switch(propAsset.type) { - case 'config' : - propValue = asset.resolveConfigAsset(config[propName]); - break; - - // :TODO: handle @art (e.g. text : @art ...) - - default : - propValue = propValue = conf[propName]; - break; - - - } - } else { - propValue = conf[propName]; - } - - if(!_.isUndefined(propValue)) { - if(setter) { - setter(propValue); - } else { - view[propName] = propValue; - } - } - } - } - */ - - //setViewProp('width', function(v) { view.setWidth(parseInt(v, 10)); }); - //setViewProp('height', function(v) { view.setHeight(parseInt(v, 10)); }); - //setViewProp('itemSpacing', function(v) { view.setItemSpacing(v); }); - //setViewProp('items', function(v) { view.setItems(v); }); - //setViewProp('text', function(v) { view.setText(v); }); - //setViewProp('textStyle'); - //setViewProp('focusTextStyle'); - //setViewProp('textMaskChar', function(v) { view.textMaskChar = v.substr(0, 1); }); - //setViewProp('justify'); - //setViewProp('textOverflow'); - //setViewProp('maskPattern', function(v) { view.setMaskPattern(v); }); - //setViewProp('maxLength'); - //setViewProp('hotKeys', function(v) { view.setHotKeys(v); }); - //setViewProp('argName', function(v) { view.submitArgName = v; }); - - // :TODO: better yet, just loop through properties directly from the JSON and - // call setPropertyValue(). View should be responsible for any conversions, e.g. - // boolean vs maskchar for 'password', etc. - - /* - [ - 'width', 'height', - 'itemSpacing', 'items', - 'text', 'textStyle', 'focusTextStyle', 'textMaskChar', - 'justify', 'textOverflow', - 'maskPattern', - 'maxLength', - 'fillChar', - 'password', - ].forEach(function pn(thePropName) { - setViewProperty2(thePropName); - }); - - // - // styleSGRx: 1..25 - // - for(var i = 1; i <= 25; i++) { - // :TODO: fix function in loop - setViewProp('styleSGR' + i, function(v) { - if(_.isObject(v)) { - view['styleSGR' + i] = ansi.getSGRFromGraphicRendition(v, true); - } else if(_.isString(v)) { - view['styleSGR' + i] = ansi.fromPipeCode(v); - } - }); - } - - setViewProp('fillChar', function(v) { - if(_.isNumber(v)) { - view.fillChar = String.fromCharCode(v); - } else if(_.isString(v)) { - view.fillChar = v.substr(0, 1); - } - }); - - setViewProp('password', function(v) { - if(true === v) { - view.textMaskChar = self.client.currentTheme.helpers.getPasswordChar(); - } - }); - - setViewProp('submit', function(v) { - if(_.isBoolean(v)) { - view.submit = v; - } else { - view.submit = _.isArray(v) && v.length > 0; - } - }); - */ - + } }; this.applyViewConfig = function(config, cb) { @@ -373,7 +195,9 @@ function ViewController(options) { }); }; - this.attachClientEvents(); + if(!options.detached) { + this.attachClientEvents(); + } } util.inherits(ViewController, events.EventEmitter); @@ -420,6 +244,14 @@ ViewController.prototype.getFocusedView = function() { return this.focusedView; }; +ViewController.prototype.removeFocus = function() { + var v = this.getFocusedView(); + if(v) { + v.setFocus(false); + this.focusedView = null; + } +}; + ViewController.prototype.switchFocus = function(id) { if(this.focusedView && this.focusedView.acceptsFocus) { this.switchFocusEvent('leave', this.focusedView); @@ -709,6 +541,48 @@ ViewController.prototype.formatMCIString = function(format) { }); }; +ViewController.prototype.getFormData = function() { + /* + Example form data: + { + id : 0, + submitId : 1, + value : { + "1" : "hurp", + "2" : [ 'a', 'b', ... ], + "3" 2, + "pants" : "no way" + } + + } + */ + var formData = { + id : this.formId, + submitId : this.focusedView.id, + value : {}, + }; + + var viewData; + var view; + for(var id in this.views) { + try { + view = this.views[id]; + viewData = view.getData(); + if(!_.isUndefined(viewData)) { + if(_.isString(view.submitArgName)) { + formData.value[view.submitArgName] = viewData; + } else { + formData.value[id] = viewData; + } + } + } catch(e) { + Log.error(e); // :TODO: Log better ;) + } + } + + return formData; +} + /* ViewController.prototype.formatMenuArgs = function(args) { var self = this; diff --git a/mods/art/demo_fse_netmail_body.ans b/mods/art/demo_fse_netmail_body.ans new file mode 100644 index 00000000..1c545573 Binary files /dev/null and b/mods/art/demo_fse_netmail_body.ans differ diff --git a/mods/art/demo_fse_netmail_header.ans b/mods/art/demo_fse_netmail_header.ans new file mode 100644 index 00000000..47ef04e6 Binary files /dev/null and b/mods/art/demo_fse_netmail_header.ans differ diff --git a/mods/fse.js b/mods/fse.js index 9c6952f8..c9df0b27 100644 --- a/mods/fse.js +++ b/mods/fse.js @@ -22,16 +22,22 @@ function FullScreenEditorModule(options) { var self = this; this.menuConfig = options.menuConfig; this.editorType = this.menuConfig.config.editorType; + this.artNames = [ 'header', 'body', 'footerEdit', 'footerEditMenu', 'footerView' ]; + this.editorMode = 'edit'; // :TODO: This needs to be passed in via args this.initSequence = function() { var mciData = { }; + var art = self.menuConfig.config.art; + assert(_.isObject(art)); + // :TODO: async.series here? async.waterfall( [ function beforeDisplayArt(callback) { self.beforeArt(); callback(null); }, + /* function displayMainArt(callback) { if(_.isString(self.menuConfig.art)) { self.displayArtAsset(self.menuConfig.art, function frameDisplayed(err, artData) { @@ -42,6 +48,23 @@ function FullScreenEditorModule(options) { callback(null); // :TODO: should probably throw error... can't do much without this } }, + */ + function displayArtHeaderAndBody(callback) { + assert(_.isString(art.header)); + assert(_.isString(art.body)); + + async.eachSeries( [ 'header', 'body' ], function dispArt(n, next) { + self.displayArtAsset(art[n], function artDisplayed(err, artData) { + mciData[n] = artData; + next(err); + }); + }, function complete(err) { + callback(err); + }); + }, + function displayArtFooter(callback) { + callback(null); + }, function afterArtDisplayed(callback) { self.mciReady(mciData); callback(null); @@ -53,6 +76,43 @@ function FullScreenEditorModule(options) { ); }; + this.mciReadyHandlerNetMail = function(mciData) { + + var menuLoadOpts = { callingMenu : self }; + + async.series( + [ + function header(callback) { + menuLoadOpts.formId = 0; + menuLoadOpts.mciMap = mciData.header.mciMap; + + self.addViewController( + 'header', + new ViewController( { client : self.client } ) + ).loadFromMenuConfig(menuLoadOpts, function headerReady(err) { + callback(err); + }); + }, + function body(callback) { + menuLoadOpts.formId = 1; + menuLoadOpts.mciMap = mciData.body.mciMap; + + self.addViewController( + 'body', + new ViewController( { client : self.client } ) + ).loadFromMenuConfig(menuLoadOpts, function bodyReady(err) { + callback(err); + }); + } + ], + function complete(err) { + self.viewControllers.body.removeFocus(); // :TODO: Change vc to allow *not* setting focus @ create + self.viewControllers.header.switchFocus(1); + } + ); + }; + + /* this.mciReadyHandlerNetMail = function(mciData) { var mainVc = self.addViewController('main', new ViewController( { client : self.client } )); @@ -65,8 +125,13 @@ function FullScreenEditorModule(options) { mainVc.loadFromMenuConfig(menuLoadOpts, function viewsReady(err) { }); }; + */ this.menuMethods = { + headerSubmit : function(formData, extraArgs) { + console.log('submit header:\n' + JSON.stringify(self.viewControllers.header.getFormData())) + self.viewControllers.body.switchFocus(1); + }, editorEscPressed : function(formData, extraArgs) { } diff --git a/mods/menu.json b/mods/menu.json index 6f2057b3..80059697 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -471,8 +471,66 @@ "art" : "demo_fse_local_user.ans", "options" : { "cls" : true }, "config" : { - "editorType" : "netMail" + "editorType" : "netMail", + "art" : { + "header" : "demo_fse_netmail_header.ans", + "body" : "demo_fse_netmail_body.ans", + "footerEdit" : "demo_fse_netmail_footer_edit.ans", + "footerEditMenu" : "demo_fse_netmail_footer_edit_menu.ans", + "footerView" : "demo_fse_netmail_footer_view.ans" + } }, + "form" : { + "0" : { + "ET1ET2ET3" : { + "mci" : { + "ET1" : { + // :TODO: from/to may be set by args + // :TODO: focus may change dep on view vs edit + "width" : 36, + "focus" : true + }, + "ET2" : { + "width" : 36 + }, + "ET3" : { + "width" : 65, + "maxLength" : 72, + "submit" : [ "enter" ] + } + }, + "submit" : { + "3" : [ + { + "value" : { "3" : null }, + "action" : "@method:headerSubmit" + } + ] + } + } + }, + "1" : { + "MT1" : { + "mci" : { + "MT1" : { + "width" : 79, + "height" : 16, + "text" : "", // :TODO: should not be req. + "submit" : [ "escape" ] + } + }, + "submit" : { + "*" : [ + { + "value" : 1, + "action" : "@method:editorEscPressed" + } + ] + } + } + } + } + /* "form" : { "0" : { "ET1ET2MT3" : { @@ -504,6 +562,7 @@ } } } + */ } /*