diff --git a/core/client_term.js b/core/client_term.js index 67259ef2..445b5d35 100644 --- a/core/client_term.js +++ b/core/client_term.js @@ -67,6 +67,7 @@ function ClientTerminal(output) { // XTERM // * PuTTY // LINUX + // * JuiceSSH - also via TERM= // QNX // SCREEN // * ConnectBot @@ -134,6 +135,9 @@ ClientTerminal.prototype.write = function(s, convertLineFeeds) { this.output.write(this.iconv.encode(s, this.outputEncoding)); }; */ + +// :TODO: probably need to update these to convert IAC (0xff) -> IACIAC (escape it) + ClientTerminal.prototype.write = function(s, convertLineFeeds) { this.output.write(this.encode(s, convertLineFeeds)); }; diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index 3e1c4725..4a3cf3b8 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -10,7 +10,6 @@ var SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView; var ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView; var MaskEditTextView = require('./mask_edit_text_view.js').MaskEditTextView; var StatusBarView = require('./status_bar_view.js').StatusBarView; - var MultiLineEditTextView = require('./multi_line_edit_text_view.js').MultiLineEditTextView; var Config = require('./config.js').config; @@ -210,7 +209,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { default : options.text = this.getPredefinedViewLabel(mci.code); - if(options.text) { + if(_.isString(options.text)) { view = new TextView(options); } break; diff --git a/core/message.js b/core/message.js new file mode 100644 index 00000000..bfd605f1 --- /dev/null +++ b/core/message.js @@ -0,0 +1,6 @@ +/* jslint node: true */ +'use strict'; + +function Message(options) { + +} \ No newline at end of file diff --git a/core/multi_line_edit_text_view.js b/core/multi_line_edit_text_view.js index 92411a90..0e80e7c9 100644 --- a/core/multi_line_edit_text_view.js +++ b/core/multi_line_edit_text_view.js @@ -100,12 +100,13 @@ function MultiLineEditTextView(options) { // * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt // // This seems overkill though, so let's default to 4 :) + // :TODO: what shoudl this really be? Maybe 8 is OK // - this.tabWidth = _.isNumber(options.tabWidth) ? options.tabWidth : 4; + this.tabWidth = _.isNumber(options.tabWidth) ? options.tabWidth : 4; this.textLines = []; this.topVisibleIndex = 0; - this.mode = options.mode || 'edit'; // edit | preview + this.mode = options.mode || 'edit'; // edit | preview | read-only // // cursorPos represents zero-based row, col positions @@ -1052,7 +1053,7 @@ MultiLineEditTextView.prototype.setText = function(text) { //this.textLines = [ { text : '' } ]; //this.insertRawText(''); //text = "Tab:\r\n\tA\tB\tC\tD\tE\tF\tG\r\n reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally long word!!!"; - text = require('fs').readFileSync('/home/bashby/Downloads/test_text.txt', { encoding : 'utf-8'}); + text = require('fs').readFileSync('/home/nuskooler/Downloads/test_text.txt', { encoding : 'utf-8'}); this.insertRawText(text);//, 0, 0); this.cursorEndOfDocument(); diff --git a/core/servers/telnet.js b/core/servers/telnet.js index b7efcb80..79a31ebc 100644 --- a/core/servers/telnet.js +++ b/core/servers/telnet.js @@ -598,7 +598,9 @@ TelnetClient.prototype.handleSbCommand = function(evt) { Log.debug({ termHeight : self.term.termHeight, source : 'NEW-ENVIRON'}, 'Window height updated'); } else { if(name in self.term.env) { - assert(evt.type === SB_COMMANDS.INFO); + assert( + SB_COMMANDS.INFO === evt.type || SB_COMMANDS.IS === evt.type, + 'Unexpected type: ' + evt.type); Log.warn( { varName : name, value : evt.envVars[name], existingValue : self.term.env[name] }, diff --git a/core/view.js b/core/view.js index 1cfa46dd..b7216f9f 100644 --- a/core/view.js +++ b/core/view.js @@ -70,6 +70,7 @@ function View(options) { this.dimens = { width : 0, height : 0 }; } + // :TODO: Just use styleSGRx for these, e.g. styleSGR0, styleSGR1 = norm/focus this.ansiSGR = options.ansiSGR || ansi.getSGRFromGraphicRendition( { fg : 39, bg : 49 }, true); this.ansiFocusSGR = options.ansiFocusSGR || this.ansiSGR; diff --git a/core/view_controller.js b/core/view_controller.js index 054d051f..d7ba71ba 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -32,8 +32,7 @@ function ViewController(options) { this.client = options.client; this.views = {}; // map of ID -> view this.formId = options.formId || 0; - this.mciViewFactory = new MCIViewFactory(this.client); - //this.submitKeyMap = {}; + this.mciViewFactory = new MCIViewFactory(this.client); // :TODO: can this not be a singleton? this.actionKeyMap = {}; @@ -60,15 +59,6 @@ function ViewController(options) { return; } - - /* - var submitViewId = self.submitKeyMap[key.name]; - if(submitViewId) { - self.switchFocus(submitViewId); - self.submitForm(); - return; - } - */ } if(self.focusedView && self.focusedView.acceptsInput) { @@ -83,7 +73,7 @@ function ViewController(options) { self.nextFocus(); break; - case 'accept' : // :TODO: consider naming this 'done' + case 'accept' : if(self.focusedView && self.focusedView.submit) { self.submitForm(); } else { @@ -146,7 +136,7 @@ function ViewController(options) { if(propAsset) { switch(propAsset.type) { case 'config' : - propValue = asset.resolveConfigAsset(config[propName]); + propValue = asset.resolveConfigAsset(conf[propName]); break; // :TODO: handle @art (e.g. text : @art ...) @@ -196,18 +186,6 @@ function ViewController(options) { initialFocusId = viewId; } - /* - if(view.submit) { - submitId = viewId; - - if(_.isArray(mciConf.submit)) { - for(var i = 0; i < mciConf.submit.length; i++) { - self.submitKeyMap[mciConf.submit[i]] = viewId; - } - } - } - */ - nextItem(null); }, function complete(err) { diff --git a/mods/art/demo_fse_netmail_help.ans b/mods/art/demo_fse_netmail_help.ans new file mode 100644 index 00000000..f24025f8 Binary files /dev/null and b/mods/art/demo_fse_netmail_help.ans differ diff --git a/mods/fse.js b/mods/fse.js index fb8b0cd8..963f7dfc 100644 --- a/mods/fse.js +++ b/mods/fse.js @@ -1,13 +1,15 @@ /* jslint node: true */ 'use strict'; -var MenuModule = require('../core/menu_module.js').MenuModule; -var ViewController = require('../core/view_controller.js').ViewController; -var ansi = require('../core/ansi_term.js'); +var MenuModule = require('../core/menu_module.js').MenuModule; +var ViewController = require('../core/view_controller.js').ViewController; +var ansi = require('../core/ansi_term.js'); +var theme = require('../core/theme.js'); +var MultiLineEditTextView = require('../core/multi_line_edit_text_view.js').MultiLineEditTextView; -var async = require('async'); -var assert = require('assert'); -var _ = require('lodash'); +var async = require('async'); +var assert = require('assert'); +var _ = require('lodash'); exports.getModule = FullScreenEditorModule; @@ -39,7 +41,9 @@ function FullScreenEditorModule(options) { body : 1, footerEdit : 2, footerEditMenu : 3, - fotoerView : 4, + footerView : 4, + + help : 50, }[name]; }; @@ -79,6 +83,44 @@ function FullScreenEditorModule(options) { ); }; + this.redrawScreen = function(options, cb) { + var comps = [ 'header', 'body' ]; + var art = self.menuConfig.config.art; + + self.client.term.rawWrite(ansi.resetScreen()); + + async.series( + [ + function displayHeaderAndBody(callback) { + async.eachSeries( comps, function dispArt(n, next) { + self.displayArtAsset(art[n], function artDisplayed(err, artData) { + next(err); + }); + }, function complete(err) { + callback(err); + }); + }, + function displayFooter(callback) { + // we have to treat the footer special + self.redrawFooter( { clear : false, footerName : self.getFooterName() }, function footerDisplayed(err) { + callback(err); + }); + }, + function refreshViews(callback) { + comps.push(self.getFooterName()); + + comps.forEach(function artComp(n) { + self.viewControllers[n].redrawAll(); + }); + } + ], + function complete(err) { + cb(err); + } + ); + }; + + this.switchFooter = function(cb) { var footerName = self.getFooterName(); @@ -231,6 +273,52 @@ function FullScreenEditorModule(options) { } }; + this.displayHelp = function() { + // + // Replace body area with a temporary read-only MultiLineEditText + // with help contents. ESC or 'Q' closes back to previous state. + // + var formId = self.getFormId('help'); + + if(_.isUndefined(self.viewControllers.help)) { + self.addViewController('help', new ViewController( { client : self.client, formId : formId } )); + + var helpViewOpts = { + position : self.getBodyView().position, + //dimens : self.getBodyView().dimens, + acceptsFocus : true, + acceptsInput : true, + id : 1, + client : self.client, + ansiSGR : ansi.sgr( [ 'normal', 'reset' ] ), // :TODO: use a styleSGRx here; default to white on black + }; + + var helpView = new MultiLineEditTextView(helpViewOpts); + // :TODO: this is to work around a bug... dimens in ctor should be enough! + helpView.setWidth(self.getBodyView().dimens.width); + helpView.setHeight(self.getBodyView().dimens.height); + helpView.setText('Some help text...') + + self.viewControllers.help.addView(helpView); + self.viewControllers.help.switchFocus(1); + } + + self.viewControllers.help.redrawAll(); + }; + + this.displayHelp2 = function() { + self.client.term.rawWrite(ansi.resetScreen()); + + theme.displayThemeArt( { name : self.menuConfig.config.art.help, client : self.client }, + function artDisplayed(err, artData) { + self.client.waitForKeyPress(function keyPress(ch, key) { + self.redrawScreen(); + self.viewControllers.footerEditMenu.setFocus(true); + }); + } + ); + }; + this.observeEditEvents = function() { var bodyView = self.getBodyView(); @@ -281,6 +369,12 @@ function FullScreenEditorModule(options) { }, editModeMenu : function(formData, extraArgs) { console.log('menu ' + formData.value['1']) + + if(3 == formData.value['1']) { + console.log('Display help...') + self.viewControllers.footerEditMenu.setFocus(false); + self.displayHelp2(); + } } }; } diff --git a/mods/menu.json b/mods/menu.json index 2f5b772a..e8490200 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -502,7 +502,8 @@ "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" + "footerView" : "demo_fse_netmail_footer_view.ans", + "help" : "demo_fse_netmail_help.ans" } }, "form" : { @@ -616,6 +617,17 @@ } */ } + }, + "5" : { + "ML1" : { + "mci" : { + "ML1" : { + "width" : 79, + "height" : 17, + "text" : "" // :TODO: fixme + } + } + } } } /*