* Artwork for NU-MAYA help, updated quote builder, etc.

* Fix some typos
* Fix message getQuoteLines()
* Quote builder fully functional
* MLTEV emits more information in position events
* Action keys can how handle plain characters that don't have full key object, e.g. "?"
* Hot keys for a lot of stuff
* WIP work on focus issue in VC.
This commit is contained in:
Bryan Ashby 2015-09-19 22:55:09 -06:00
parent d23012a201
commit a6d00b05a7
11 changed files with 157 additions and 80 deletions

View File

@ -446,6 +446,7 @@ function FullScreenEditorModule(options) {
case 'view' : case 'view' :
self.switchToFooter(); self.switchToFooter();
//self.observeViewPosition();
break; break;
} }
@ -558,7 +559,7 @@ function FullScreenEditorModule(options) {
function helpDisplayed(err, artData) { function helpDisplayed(err, artData) {
self.client.waitForKeyPress(function keyPress(ch, key) { self.client.waitForKeyPress(function keyPress(ch, key) {
self.redrawScreen(); self.redrawScreen();
self.viewControllers.footerEditorMenu.setFocus(true); self.viewControllers[self.getFooterName()].setFocus(true);
}); });
} }
); );
@ -636,6 +637,14 @@ function FullScreenEditorModule(options) {
}); });
}; };
/*
this.observeViewPosition = function() {
self.viewControllers.body.getView(1).on('edit position', function positionUpdate(pos) {
console.log(pos.percent + ' / ' + pos.below)
});
};
*/
this.switchToHeader = function() { this.switchToHeader = function() {
self.viewControllers.body.setFocus(false); self.viewControllers.body.setFocus(false);
self.viewControllers.header.switchFocus(2); // to self.viewControllers.header.switchFocus(2); // to
@ -765,6 +774,10 @@ function FullScreenEditorModule(options) {
// MLTEV won't get key events -- we need to handle them all here? // MLTEV won't get key events -- we need to handle them all here?
// ...up/down, page up/page down... both should go by pages // ...up/down, page up/page down... both should go by pages
// ...Next/Prev/Etc. here // ...Next/Prev/Etc. here
},
viewModeMenuHelp : function(formData, extraArgs) {
self.viewControllers.footerView.setFocus(false);
self.displayHelp();
} }
}; };

View File

@ -201,6 +201,8 @@ function handleAction(client, formData, conf) {
var currentModule = client.currentMenuModule; var currentModule = client.currentMenuModule;
if(_.isFunction(currentModule.menuMethods[actionAsset.asset])) { if(_.isFunction(currentModule.menuMethods[actionAsset.asset])) {
currentModule.menuMethods[actionAsset.asset](formData, conf.extraArgs); currentModule.menuMethods[actionAsset.asset](formData, conf.extraArgs);
} else {
client.log.warn( { method : actionAsset.asset }, 'Method does not exist in module');
} }
} }
} }

View File

@ -244,6 +244,7 @@ Message.prototype.persist = function(cb) {
); );
}; };
// :TODO: Update this to use a FTN module, e.g. ftn.getQuotePrefix(name)
Message.prototype.getFTNQuotePrefix = function(source) { Message.prototype.getFTNQuotePrefix = function(source) {
source = source || 'fromUserName'; source = source || 'fromUserName';
@ -275,22 +276,29 @@ Message.prototype.getQuoteLines = function(width, options) {
var quoteLines = []; var quoteLines = [];
var origLines = this.message var origLines = this.message
.trim()
.replace(/\b/g, '') .replace(/\b/g, '')
.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g); .split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g);
var wrapOpts = { var quotePrefix = ''; // we need this init even if blank
width : width,
tabHandling : 'expand',
tabWidth : 4,
};
var quotePrefix;
if(options.includePrefix) { if(options.includePrefix) {
quotePrefix = ' ' + this.getFTNQuotePrefix(options.prefixSource || 'fromUserName') + '> '; quotePrefix = ' ' + this.getFTNQuotePrefix(options.prefixSource || 'fromUserName') + '> ';
} }
var wrapOpts = {
width : width - quotePrefix.length,
tabHandling : 'expand',
tabWidth : 4,
};
function addPrefix(l) {
return quotePrefix + l;
}
var wrapped;
for(var i = 0; i < origLines.length; ++i) { for(var i = 0; i < origLines.length; ++i) {
Array.prototype.push.apply(quoteLines, wordWrapText(quotePrefix + origLines[i], wrapOpts).wrapped); wrapped = wordWrapText(origLines[i], wrapOpts).wrapped;
Array.prototype.push.apply(quoteLines, _.map(wrapped, addPrefix));
} }
return quoteLines; return quoteLines;

View File

@ -365,7 +365,7 @@ function MultiLineEditTextView(options) {
self.updateTextWordWrap(index); self.updateTextWordWrap(index);
self.redrawRows(self.cursorPos.row, self.dimens.height); self.redrawRows(self.cursorPos.row, self.dimens.height);
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
} else if('delete line' === operation) { } else if('delete line' === operation) {
// //
// Delete a visible line. Note that this is *not* the "physical" line, or // Delete a visible line. Note that this is *not* the "physical" line, or
@ -401,7 +401,7 @@ function MultiLineEditTextView(options) {
if(isLastLine) { if(isLastLine) {
self.cursorEndOfPreviousLine(); self.cursorEndOfPreviousLine();
} else { } else {
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
} }
} }
}; };
@ -438,7 +438,7 @@ function MultiLineEditTextView(options) {
self.cursorPos.col += cursorOffset; self.cursorPos.col += cursorOffset;
self.client.term.rawWrite(ansi.right(cursorOffset)); self.client.term.rawWrite(ansi.right(cursorOffset));
} else { } else {
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
} }
} else { } else {
// //
@ -561,7 +561,7 @@ function MultiLineEditTextView(options) {
}; };
}; };
this.moveClientCusorToCursorPos = function() { this.moveClientCursorToCursorPos = function() {
var absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col); var absPos = self.getAbsolutePosition(self.cursorPos.row, self.cursorPos.col);
self.client.term.rawWrite(ansi.goto(absPos.row, absPos.col)); self.client.term.rawWrite(ansi.goto(absPos.row, absPos.col));
}; };
@ -669,14 +669,14 @@ function MultiLineEditTextView(options) {
} else { } else {
self.cursorPos.col = 0; self.cursorPos.col = 0;
} }
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
self.emitEditPosition(); self.emitEditPosition();
}; };
this.keyPressEnd = function() { this.keyPressEnd = function() {
self.cursorPos.col = self.getTextEndOfLineColumn(); self.cursorPos.col = self.getTextEndOfLineColumn();
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
self.emitEditPosition(); self.emitEditPosition();
}; };
@ -687,7 +687,7 @@ function MultiLineEditTextView(options) {
self.adjustCursorIfPastEndOfLine(true); self.adjustCursorIfPastEndOfLine(true);
} else { } else {
self.cursorPos.row = 0; self.cursorPos.row = 0;
self.moveClientCusorToCursorPos(); // :TODO: ajust if eol, etc. self.moveClientCursorToCursorPos(); // :TODO: ajust if eol, etc.
} }
self.emitEditPosition(); self.emitEditPosition();
@ -817,7 +817,7 @@ function MultiLineEditTextView(options) {
} }
if(forceUpdate) { if(forceUpdate) {
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
} }
}; };
@ -874,7 +874,7 @@ function MultiLineEditTextView(options) {
self.cursorPos = { row : 0, col : 0 }; self.cursorPos = { row : 0, col : 0 };
self.redraw(); self.redraw();
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
}; };
this.cursorEndOfDocument = function() { this.cursorEndOfDocument = function() {
@ -883,7 +883,7 @@ function MultiLineEditTextView(options) {
self.cursorPos.col = self.getTextEndOfLineColumn(); self.cursorPos.col = self.getTextEndOfLineColumn();
self.redraw(); self.redraw();
self.moveClientCusorToCursorPos(); self.moveClientCursorToCursorPos();
}; };
this.cursorBeginOfNextLine = function() { this.cursorBeginOfNextLine = function() {
@ -984,7 +984,7 @@ MultiLineEditTextView.prototype.redraw = function() {
MultiLineEditTextView.prototype.setFocus = function(focused) { MultiLineEditTextView.prototype.setFocus = function(focused) {
this.client.term.rawWrite(this.getSGRFor('text')); this.client.term.rawWrite(this.getSGRFor('text'));
this.moveClientCusorToCursorPos(); this.moveClientCursorToCursorPos();
MultiLineEditTextView.super_.prototype.setFocus.call(this, focused); MultiLineEditTextView.super_.prototype.setFocus.call(this, focused);
}; };
@ -1036,12 +1036,6 @@ var HANDLED_SPECIAL_KEYS = [
'delete line', 'delete line',
]; ];
/*
var EDIT_MODE_KEYS = [
'line feed', 'insert', 'tab', 'backspace', 'del', 'delete line'
];
*/
var PREVIEW_MODE_KEYS = [ var PREVIEW_MODE_KEYS = [
'up', 'down', 'page up', 'page down' 'up', 'down', 'page up', 'page down'
]; ];
@ -1078,6 +1072,13 @@ MultiLineEditTextView.prototype.getTextEditMode = function() {
}; };
MultiLineEditTextView.prototype.getEditPosition = function() { MultiLineEditTextView.prototype.getEditPosition = function() {
return { row : this.getTextLinesIndex(this.cursorPos.row), col : this.cursorPos.col } var currentIndex = this.getTextLinesIndex() + 1;
return {
row : this.getTextLinesIndex(this.cursorPos.row),
col : this.cursorPos.col,
percent : Math.floor(((currentIndex / this.textLines.length) * 100)),
below : this.getRemainingLinesBelowRow(),
};
}; };

View File

@ -42,21 +42,20 @@ function ViewController(options) {
// Process key presses treating form submit mapped keys special. // Process key presses treating form submit mapped keys special.
// Everything else is forwarded on to the focused View, if any. // Everything else is forwarded on to the focused View, if any.
// //
if(key) { var actionForKey = key ? self.actionKeyMap[key.name] : self.actionKeyMap[ch];
var actionForKey = self.actionKeyMap[key.name] //var actionForKey = self.actionKeyMap[key.name] || self.actionKeyMap[ch];
if(actionForKey) { if(actionForKey) {
if(_.isNumber(actionForKey.viewId)) { if(_.isNumber(actionForKey.viewId)) {
// //
// Key works on behalf of a view -- switch focus & submit // Key works on behalf of a view -- switch focus & submit
// //
self.switchFocus(actionForKey.viewId); self.switchFocus(actionForKey.viewId);
self.submitForm(key); self.submitForm(key);
} else if(_.isString(actionForKey.action)) { } else if(_.isString(actionForKey.action)) {
menuUtil.handleAction( menuUtil.handleAction(
self.client, self.client,
{ key : key }, // formData { ch : ch, key : key }, // formData
actionForKey); // action block actionForKey); // action block
}
} }
} }
@ -298,6 +297,21 @@ function ViewController(options) {
if(!options.detached) { if(!options.detached) {
this.attachClientEvents(); this.attachClientEvents();
} }
this.setViewFocusWithEvents = function(view, focused) {
if(!view || !view.acceptsFocus) {
return;
}
if(focused) {
self.switchFocusEvent('return', view);
self.focusedView = view;
} else {
self.switchFocusEvent('leave', view);
}
view.setFocus(focused);
};
} }
util.inherits(ViewController, events.EventEmitter); util.inherits(ViewController, events.EventEmitter);
@ -358,23 +372,19 @@ ViewController.prototype.setFocus = function(focused) {
} else { } else {
this.detachClientEvents(); this.detachClientEvents();
} }
// :TODO: without this, setFocus(false) is broken (doens't call focus events); with it, FSE menus break!!
// this.setViewFocusWithEvents(this.focusedView, focused);
}; };
ViewController.prototype.switchFocus = function(id) { ViewController.prototype.switchFocus = function(id) {
this.setFocus(true); // ensure events are attached this.setFocus(true); // ensure events are attached
if(this.focusedView && this.focusedView.acceptsFocus) { // remove from old
this.switchFocusEvent('leave', this.focusedView); this.setViewFocusWithEvents(this.focusedView, false);
this.focusedView.setFocus(false);
}
var view = this.getView(id); // set to new
if(view && view.acceptsFocus) { this.setViewFocusWithEvents(this.getView(id), true);
this.switchFocusEvent('return', view);
this.focusedView = view;
this.focusedView.setFocus(true);
}
}; };
ViewController.prototype.nextFocus = function() { ViewController.prototype.nextFocus = function() {
@ -624,7 +634,7 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) {
callback(null); callback(null);
return; return;
} }
formConfig.actionKeys.forEach(function akEntry(ak) { formConfig.actionKeys.forEach(function akEntry(ak) {
// //
// * 'keys' must be present and be an array of key names // * 'keys' must be present and be an array of key names

View File

@ -439,7 +439,7 @@
footerEdit: demo_fse_netmail_footer_edit.ans footerEdit: demo_fse_netmail_footer_edit.ans
footerEditMenu: demo_fse_netmail_footer_edit_menu.ans footerEditMenu: demo_fse_netmail_footer_edit_menu.ans
footerView: MSGVFTR footerView: MSGVFTR
help: demo_fse_netmail_help.ans help: MSGVHLP
}, },
editorMode: view editorMode: view
editorType: area editorType: area
@ -502,34 +502,48 @@
} }
} }
}, },
"4" : { 4: {
"mci" : { mci: {
"HM1" : { HM1: {
// (P)rev/(N)ext/Post/(R)eply/(Q)uit/(?)Help // :TODO: (#)Jump/(L)Index (msg list)/Last
// (#)Jump/(L)Index (msg list)/Last items: [
"items" : [ "Prev", "Next", "Reply", "Quit", "Help" ] // (P)revious
Prev
// (N)ext
Next
// (R)reply
Reply
// (Q)uit (ESC)
Quit
// (?)Help
Help
]
} }
}, },
"submit" : { "submit" : {
"*" : [ "*" : [
{ {
"value" : { "1" : 0 }, value: { 1: 0 }
"action" : "@method:prevMessage" action: @method:prevMessage"
}, }
{ {
"value" : { "1" : 1 }, value: { 1: 1 }
"action" : "@method:nextMessage" action: @method:nextMessage
}, }
{ {
value: { 1: 2 } value: { 1: 2 }
action: @method:replyMessage action: @method:replyMessage
extraArgs: { extraArgs: {
menu: messageAreaReplyPost menu: messageAreaReplyPost
} }
}, }
{ {
"value" : { "1" : 3 }, value: { 1: 3 }
"action" : "@menu:messageArea" action: @menu:messageArea
}
{
value: { 1: 4 }
action: @method:viewModeMenuHelp
} }
] ]
}, },
@ -549,11 +563,6 @@
keys: [ "n", "shift + n" ] keys: [ "n", "shift + n" ]
action: @method:nextMessage action: @method:nextMessage
} }
{
keys: [ "escape", "q", "shift + q" ]
action: @menu:messageArea
}
// :TODO: why the fuck is 'r' not working but 'n' for example does?
{ {
keys: [ "r", "shift + r" ] keys: [ "r", "shift + r" ]
action: @method:replyMessage action: @method:replyMessage
@ -561,6 +570,14 @@
menu: messageAreaReplyPost menu: messageAreaReplyPost
} }
} }
{
keys: [ "escape", "q", "shift + q" ]
action: @menu:messageArea
}
{
keys: [ "?" ]
action: @method:viewModeMenuHelp
}
{ {
"keys" : [ "down arrow", "up arrow", "page up", "page down" ], "keys" : [ "down arrow", "up arrow", "page up", "page down" ],
"action" : "@method:movementKeyPressed" "action" : "@method:movementKeyPressed"
@ -578,8 +595,7 @@
quote: MSGQUOT quote: MSGQUOT
footerEditor: MSGEFTR footerEditor: MSGEFTR
footerEditorMenu: MSGEMFT footerEditorMenu: MSGEMFT
// :TODO: fix help help: MSGEHLP
help: demo_fse_netmail_help.ans
} }
editorMode: edit editorMode: edit
editorType: area editorType: area
@ -602,9 +618,10 @@
argName: subject argName: subject
maxLength: 72 maxLength: 72
submit: true submit: true
textOverflow: ...
} }
TL4: { TL4: {
// :TODO: this is for RE: line // :TODO: this is for RE: line (NYI)
width: 27 width: 27
textOverflow: ... textOverflow: ...
} }
@ -667,10 +684,27 @@
keys: [ "escape" ] keys: [ "escape" ]
action: @method:editModeEscPressed action: @method:editModeEscPressed
} }
{
keys: [ "s", "shift + s" ]
action: @method:replySave
}
{
keys: [ "d", "shift + d" ]
action: @method:replyDiscard
}
{
keys: [ "q", "shift + q" ]
action: @method:editModeMenuQuote
}
{
keys: [ "?" ]
action: @method:editModeMenuHelp
}
] ]
} }
} }
// Quote builder
5: { 5: {
mci: { mci: {
MT1: { MT1: {
@ -713,7 +747,7 @@
body: MSGBODY body: MSGBODY
footerEditor: MSGEFTR footerEditor: MSGEFTR
footerEditorMenu: MSGEMFT footerEditorMenu: MSGEMFT
help: demo_fse_netmail_help.ans help: MSGEHLP
}, },
editorMode: edit editorMode: edit
editorType: area editorType: area

View File

@ -70,6 +70,11 @@ AreaPostFSEModule.prototype.enter = function(client) {
AreaPostFSEModule.prototype.validateToUserName = function(un, cb) { AreaPostFSEModule.prototype.validateToUserName = function(un, cb) {
var self = this; var self = this;
if(!un) {
cb(new Error('Username must be supplied!'));
return;
}
if(!self.isLocalEmail()) { if(!self.isLocalEmail()) {
cb(null); cb(null);
return; return;

View File

@ -60,8 +60,12 @@ function AreaViewFSEModule(options) {
case 'down arrow' : bodyView.scrollDocumentUp(); break; case 'down arrow' : bodyView.scrollDocumentUp(); break;
case 'up arrow' : bodyView.scrollDocumentDown(); break; case 'up arrow' : bodyView.scrollDocumentDown(); break;
case 'page up' : bodyView.keyPressPageUp(); break; case 'page up' : bodyView.keyPressPageUp(); break;
case 'page down' : bodyView.keyPressPageDown(); break; case 'page down' : bodyView.keyPressPageDown(); break;
} }
// :TODO: need to stop down/page down if doing so would push the last
// visible page off the screen at all
}; };
this.menuMethods.replyMessage = function(formData, extraArgs) { this.menuMethods.replyMessage = function(formData, extraArgs) {

Binary file not shown.

Binary file not shown.

Binary file not shown.