Merge branch 'master' of ssh://numinibsd/git/base/enigma-bbs

This commit is contained in:
Bryan Ashby 2016-09-04 21:37:05 -06:00
commit ab596842d6
28 changed files with 217 additions and 200 deletions

View File

@ -2,15 +2,27 @@
'use strict';
//
// ANSI Terminal Support
// ANSI Terminal Support Resources
//
// Resources:
// * http://ansi-bbs.org/
// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/ansisys.txt
// * http://en.wikipedia.org/wiki/ANSI_escape_code
// * https://github.com/chjj/term.js/blob/master/src/term.js
// * http://www.inwap.com/pdp10/ansicode.txt
// ANSI-BBS
// * http://ansi-bbs.org/
//
// CTerm / SyncTERM
// * https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt
//
// BananaCom
// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
//
// ANSI.SYS
// * http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/ansisys.txt
// * http://academic.evergreen.edu/projects/biophysics/technotes/program/ansi_esc.htm
//
// General
// * http://en.wikipedia.org/wiki/ANSI_escape_code
// * http://www.inwap.com/pdp10/ansicode.txt
//
// Other Implementations
// * https://github.com/chjj/term.js/blob/master/src/term.js
// ENiGMA½
const miscUtil = require('./misc_util.js');

View File

@ -2,7 +2,8 @@
'use strict';
// ENiGMA½
const Config = require('./config.js').config;
const Config = require('./config.js').config;
const stringFormat = require('./string_format.js');
// base/modules
const fs = require('fs');
@ -124,7 +125,7 @@ module.exports = class ArchiveUtil {
let args = _.clone(archiver.compressArgs); // don't muck with orig
for(let i = 0; i < args.length; ++i) {
args[i] = args[i].format({
args[i] = stringFormat(args[i], {
archivePath : archivePath,
fileList : files.join(' '),
});
@ -144,7 +145,7 @@ module.exports = class ArchiveUtil {
let args = _.clone(archiver.decompressArgs); // don't muck with orig
for(let i = 0; i < args.length; ++i) {
args[i] = args[i].format({
args[i] = stringFormat(args[i], {
archivePath : archivePath,
extractPath : extractPath,
});

View File

@ -128,10 +128,10 @@ function initialize(cb) {
if(err) {
console.error('Could not create path: ' + conf.config.paths[pathKey] + ': ' + err.toString());
}
next(err);
return next(err);
});
}, function dirCreationComplete(err) {
callback(err);
return callback(err);
});
},
function basicInit(callback) {
@ -142,22 +142,19 @@ function initialize(cb) {
process.on('SIGINT', shutdownSystem);
// Init some extensions
require('string-format').extend(String.prototype, require('./string_util.js').stringFormatExtensions);
callback(null);
return callback(null);
},
function initDatabases(callback) {
database.initializeDatabases(callback);
return database.initializeDatabases(callback);
},
function initStatLog(callback) {
require('./stat_log.js').init(callback);
return require('./stat_log.js').init(callback);
},
function initThemes(callback) {
// Have to pull in here so it's after Config init
require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) {
logger.log.info({ themeCount : themeCount }, 'Themes initialized');
callback(err);
return callback(err);
});
},
function loadSysOpInformation(callback) {
@ -204,10 +201,10 @@ function initialize(cb) {
);
},
function initMCI(callback) {
require('./predefined_mci.js').init(callback);
return require('./predefined_mci.js').init(callback);
},
function readyMessageNetworkSupport(callback) {
require('./msg_network.js').startup(callback);
return require('./msg_network.js').startup(callback);
},
function readyEventScheduler(callback) {
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
@ -218,7 +215,7 @@ function initialize(cb) {
}
],
function onComplete(err) {
cb(err);
return cb(err);
}
);
}

View File

@ -292,7 +292,17 @@ function getDefaultConfig() {
},
logging : {
level : 'debug'
level : 'debug',
rotatingFile : { // set to 'disabled' or false to disable
type : 'rotating-file',
fileName : 'enigma-bbs.log',
period : '1d',
count : 3,
level : 'debug',
}
// :TODO: syslog - https://github.com/mcavage/node-bunyan-syslog
},
debug : {

View File

@ -1,6 +1,9 @@
/* jslint node: true */
'use strict';
const stringFormat = require('./string_format.js');
const events = require('events');
const _ = require('lodash');
const pty = require('ptyw.js');
@ -100,7 +103,7 @@ Door.prototype.run = function() {
let args = _.clone(self.exeInfo.args); // we need a copy so the original is not modified
for(let i = 0; i < args.length; ++i) {
args[i] = self.exeInfo.args[i].format({
args[i] = stringFormat(self.exeInfo.args[i], {
dropFile : self.exeInfo.dropFile,
node : self.exeInfo.node.toString(),
srvPort : sockServer ? sockServer.address().port.toString() : '-1',

View File

@ -2,17 +2,16 @@
'use strict';
// ENiGMA½
const MenuModule = require('../core/menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController;
const ansi = require('../core/ansi_term.js');
const theme = require('../core/theme.js');
const Message = require('../core/message.js');
const getMessageAreaByTag = require('../core/message_area.js').getMessageAreaByTag;
const updateMessageAreaLastReadId = require('../core/message_area.js').updateMessageAreaLastReadId;
const getUserIdAndName = require('../core/user.js').getUserIdAndName;
const cleanControlCodes = require('../core/string_util.js').cleanControlCodes;
const MenuModule = require('./menu_module.js').MenuModule;
const ViewController = require('./view_controller.js').ViewController;
const ansi = require('./ansi_term.js');
const theme = require('./theme.js');
const Message = require('./message.js');
const updateMessageAreaLastReadId = require('./message_area.js').updateMessageAreaLastReadId;
const getUserIdAndName = require('./user.js').getUserIdAndName;
const cleanControlCodes = require('./string_util.js').cleanControlCodes;
const StatLog = require('./stat_log.js');
const stringFormat = require('./string_format.js');
// deps
const async = require('async');
@ -851,6 +850,21 @@ function FullScreenEditorModule(options) {
});
};
this.getQuoteByHeader = function() {
let quoteFormat = this.menuConfig.config.quoteFormats;
if(Array.isArray(quoteFormat)) {
quoteFormat = quoteFormat[ Math.floor(Math.random() * quoteFormat.length) ];
} else if(!_.isString(quoteFormat)) {
quoteFormat = 'On {dateTime} {userName} said...';
}
const dtFormat = this.menuConfig.config.quoteDateTimeFormat || self.client.currentTheme.helpers.getDateTimeFormat();
return stringFormat(quoteFormat, {
dateTime : moment(self.replyToMessage.modTimestamp).format(dtFormat),
userName : self.replyToMessage.fromUserName,
});
};
this.menuMethods = {
//
// Validation stuff
@ -917,14 +931,7 @@ function FullScreenEditorModule(options) {
if(self.newQuoteBlock) {
self.newQuoteBlock = false;
// :TODO: Make date/time format avail as FSE config -- also the line itself!
var dtFormat = self.client.currentTheme.helpers.getDateTimeFormat();
quoteMsgView.addText(
'On {0} {1} said...'.format(
moment(self.replyToMessage.modTimestamp).format(dtFormat),
self.replyToMessage.fromUserName)
);
quoteMsgView.addText(self.getQuoteByHeader());
}
var quoteText = self.viewControllers.quoteBuilder.getView(3).getItem(formData.value.quote);

View File

@ -1,63 +1,74 @@
/* jslint node: true */
'use strict';
var bunyan = require('bunyan');
var paths = require('path');
var fs = require('fs');
// deps
const bunyan = require('bunyan');
const paths = require('path');
const fs = require('fs');
const _ = require('lodash');
module.exports = {
init : function() {
var Config = require('./config.js').config;
//var ringBufferLimit = miscUtil.valueWithDefault(config.logRingBufferLimit, 100);
var logPath = Config.paths.logs;
module.exports = class Log {
//
// Create something a bit more friendly if the log directory cannot be used
//
// :TODO: this seems cheesy...
var logPathError;
try {
var pathStat = fs.statSync(logPath);
if(!pathStat.isDirectory()) {
logPathError = logPath + ' is not a directory!';
}
} catch(e) {
if('ENOENT' === e.code) {
logPathError = 'No such file or directory: ' + logPath;
} else {
logPathError = e.message;
}
static init() {
const Config = require('./config.js').config;
const logPath = Config.paths.logs;
const err = this.checkLogPath(logPath);
if(err) {
console.error(err.message); // eslint-disable-line no-console
return process.exit();
}
if(logPathError) {
console.error(logPathError);
process.exit();
const logStreams = [];
if(_.isObject(Config.logging.rotatingFile)) {
Config.logging.rotatingFile.path = paths.join(logPath, Config.logging.rotatingFile.fileName);
logStreams.push(Config.logging.rotatingFile);
}
var logFile = paths.join(logPath, 'enigma-bbs.log');
const serializers = {
err : bunyan.stdSerializers.err, // handle 'err' fields with stack/etc.
};
// :TODO: make this configurable --
// user should be able to configure rotations, levels to file vs ringBuffer,
// completely disable logging, etc.
// try to remove sensitive info by default, e.g. 'password' fields
[ 'formData', 'formValue' ].forEach(keyName => {
serializers[keyName] = (fd) => Log.hideSensitive(fd);
});
this.log = bunyan.createLogger({
name : 'ENiGMA½ BBS',
streams : [
{
type : 'rotating-file',
path : logFile,
period : Config.logging.period || '1d',
count : 3,
level : Config.logging.level || 'debug',
}
/*,
{
type : 'raw',
stream : ringBuffer,
level : 'trace'
}*/
],
serializers: { err : bunyan.stdSerializers.err } // handle 'err' fields with stack/etc.
name : 'ENiGMA½ BBS',
streams : logStreams,
serializers : serializers,
});
}
static checkLogPath(logPath) {
try {
if(!fs.statSync(logPath).isDirectory()) {
return new Error(`${logPath} is not a directory`);
}
return null;
} catch(e) {
if('ENOENT' === e.code) {
return new Error(`${logPath} does not exist`);
}
return e;
}
}
static hideSensitive(obj) {
try {
//
// Use a regexp -- we don't know how nested fields we want to seek and destroy may be
//
return JSON.parse(
JSON.stringify(obj).replace(/"(password)"\s?:\s?"([^"]+)"/, (match, valueName) => {
return `"${valueName}":"********"`;
})
);
} catch(e) {
// be safe and return empty obj!
return {};
}
}
};

View File

@ -66,7 +66,7 @@ var SPECIAL_KEY_MAP_DEFAULT = {
'line feed' : [ 'return' ],
exit : [ 'esc' ],
backspace : [ 'backspace' ],
'delete' : [ 'del' ],
delete : [ 'del' ],
tab : [ 'tab' ],
up : [ 'up arrow' ],
down : [ 'down arrow' ],
@ -802,7 +802,6 @@ function MultiLineEditTextView(options) {
self.emitEditPosition();
};
//this.keyPressClearLine = function() {
this.keyPressDeleteLine = function() {
if(self.textLines.length > 0) {
self.removeCharactersFromText(

View File

@ -4,7 +4,8 @@
// ENiGMA½
const msgArea = require('./message_area.js');
const MenuModule = require('./menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController;
const ViewController = require('./view_controller.js').ViewController;
const stringFormat = require('./string_format.js');
// deps
const _ = require('lodash');
@ -120,16 +121,7 @@ function NewScanModule(options) {
// :TODO: it would be nice to cache this - must be done by conf!
const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : self.client } );
const currentArea = sortedAreas[self.currentScanAux.area];
function getFormatObj() {
return {
confName : conf.conf.name,
confDesc : conf.conf.desc,
areaName : currentArea.area.name,
areaDesc : currentArea.area.desc
};
}
//
// Scan and update index until we find something. If results are found,
// we'll goto the list module & show them.
@ -147,7 +139,12 @@ function NewScanModule(options) {
}
},
function updateStatusScanStarted(callback) {
self.updateScanStatus(self.scanStartFmt.format(getFormatObj()));
self.updateScanStatus(stringFormat(self.scanStartFmt, {
confName : conf.conf.name,
confDesc : conf.conf.desc,
areaName : currentArea.area.name,
areaDesc : currentArea.area.desc
}));
return callback(null);
},
function getNewMessagesCountInArea(callback) {

View File

@ -9,6 +9,7 @@ var ServerModule = require('../server_module.js').ServerModule;
var userLogin = require('../user_login.js').userLogin;
var enigVersion = require('../../package.json').version;
var theme = require('../theme.js');
const stringFormat = require('../string_format.js');
var ssh2 = require('ssh2');
var fs = require('fs');
@ -105,12 +106,12 @@ function SSHClient(clientConn) {
theme.getThemeArt(artOpts, function gotArt(err, artInfo) {
if(err) {
interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: ';
} else {
var newUserNameList = '"' + (Config.users.newUserNames || []).join(', ') + '"';
interactivePrompt.prompt =
'Access denied\n' +
artInfo.data.format( { newUserNames : newUserNameList } ) +
'\n' + ctx.username + '\'s password: ';
} else {
const newUserNameList = _.has(Config, 'users.newUserNames') && Config.users.newUserNames.length > 0 ?
Config.users.newUserNames.map(newName => '"' + newName + '"').join(', ') :
'(No new user names enabled!)';
interactivePrompt.prompt = `Access denied\n${stringFormat(artInfo.data, { newUserNames : newUserNameList })}\n${ctx.username}'s password'`;
}
return ctx.prompt(interactivePrompt, retryPrompt);
});

View File

@ -1,9 +1,11 @@
/* jslint node: true */
'use strict';
const EnigError = require('./enig_error.js').EnigError;
const pad = require('./string_util.js').pad;
const stylizeString = require('./string_util.js').stylizeString;
const EnigError = require('./enig_error.js').EnigError;
const pad = require('./string_util.js').pad;
const stylizeString = require('./string_util.js').stylizeString;
const renderStringLength = require('./string_util.js').renderStringLength;
const renderSubstr = require('./string_util.js').renderSubstr;
// deps
const _ = require('lodash');
@ -124,7 +126,7 @@ function getPadAlign(align) {
function formatString(value, tokens) {
const fill = tokens.fill || (tokens['0'] ? '0' : ' ');
const align = tokens.align || (tokens['0'] ? '=' : '<');
const precision = Number(tokens.precision || value.length); // :TODO: consider pipe/ANSI length
const precision = Number(tokens.precision || renderStringLength(value) + 1);
if('' !== tokens.type && 's' !== tokens.type) {
throw new ValueError(`Unknown format code "${tokens.type}" for String object`);
@ -146,7 +148,7 @@ function formatString(value, tokens) {
throw new ValueError('"=" alignment not allowed in string format specifier');
}
return pad(value.slice(0, precision), parseInt(tokens.width), fill, getPadAlign(align));
return pad(renderSubstr(value, 0, precision), Number(tokens.width), fill, getPadAlign(align));
}
const FormatNumRegExp = {
@ -167,7 +169,10 @@ function formatNumberHelper(n, precision, type) {
case 'x' : return n.toString(16);
case 'e' : return n.toExponential(precision).replace(FormatNumRegExp.ExponentRep, '$&0');
case 'f' : return n.toFixed(precision);
case 'g' : return n.toPrecision(precision || 1);
case 'g' :
// we don't want useless trailing zeros. parseFloat -> back to string fixes this for us
return parseFloat(n.toPrecision(precision || 1)).toString();
case '%' : return formatNumberHelper(n * 100, precision, 'f') + '%';
case '' : return formatNumberHelper(n, precision, 'd');
@ -276,7 +281,7 @@ const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]
function getValue(obj, path) {
const value = _.get(obj, path);
if(value) {
if(!_.isUndefined(value)) {
return _.isFunction(value) ? value() : value;
}
@ -286,9 +291,16 @@ function getValue(obj, path) {
module.exports = function format(fmt, obj) {
const re = REGEXP_BASIC_FORMAT;
let match;
let pos;
let out = '';
let objPath ;
let transformer;
let formatSpec;
let value;
let tokens;
do {
pos = re.lastIndex;
match = re.exec(fmt);
@ -298,16 +310,16 @@ module.exports = function format(fmt, obj) {
out += fmt.slice(pos, match.index);
}
const objPath = match[1];
const transformer = match[2];
const formatSpec = match[3];
objPath = match[1];
transformer = match[2];
formatSpec = match[3];
let value = getValue(obj, objPath);
value = getValue(obj, objPath);
if(transformer) {
value = transformValue(transformer, value);
}
const tokens = tokenizeFormatSpec(formatSpec || '');
tokens = tokenizeFormatSpec(formatSpec || '');
if(!isNaN(parseInt(value))) {
out += formatNumber(value, tokens);
@ -323,5 +335,5 @@ module.exports = function format(fmt, obj) {
out += fmt.slice(pos);
}
return out;
return out;
};

View File

@ -195,45 +195,6 @@ function stringFromNullTermBuffer(buf, encoding) {
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8');
}
//
// Extend String.format's object syntax with some modifiers
// e.g.: '{username!styleL33t}'.format( { username : 'Leet User' } ) -> "L33t U53r"
//
var stringFormatExtensions = {
styleUpper : function(s) {
return stylizeString(s, 'upper');
},
styleLower : function(s) {
return stylizeString(s, 'lower');
},
styleTitle : function(s) {
return stylizeString(s, 'title');
},
styleFirstLower : function(s) {
return stylizeString(s, 'first lower');
},
styleSmallVowels : function(s) {
return stylizeString(s, 'small vowels');
},
styleBigVowels : function(s) {
return stylizeString(s, 'big vowels');
},
styleSmallI : function(s) {
return stylizeString(s, 'small i');
},
styleMixed : function(s) {
return stylizeString(s, 'mixed');
},
styleL33t : function(s) {
return stylizeString(s, 'l33t');
}
// :TODO: Add padding/etc. modifiers.
};
exports.stringFormatExtensions = stringFormatExtensions;
// :TODO: Add other codes from ansi_escape_parser
const ANSI_REGEXP = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
const PIPE_REGEXP = /\|[A-Z\d]{2}/g;
@ -244,7 +205,7 @@ const ANSI_OR_PIPE_REGEXP = new RegExp(ANSI_REGEXP.source + '|' + PIPE_REGEXP.so
//
function renderSubstr(str, start, length) {
start = start || 0;
length = length || str.length - start;
length = Math.max(0, (length || str.length - start) - 1);
const re = ANSI_REGEXP;
let pos;

View File

@ -240,14 +240,6 @@ TextView.prototype.setText = function(text) {
};
*/
TextView.prototype.setFormatObject = function(obj) {
if(!_.isObject(obj) || !this.text) {
return;
}
this.setText(this.text.format(obj));
};
TextView.prototype.clearText = function() {
this.setText('');
};

View File

@ -16,7 +16,7 @@ exports.userLogin = userLogin;
function userLogin(client, username, password, cb) {
client.user.authenticate(username, password, function authenticated(err) {
if(err) {
client.log.info( { username : username }, 'Failed login attempt: %s', err);
client.log.info( { username : username, error : err.message }, 'Failed login attempt');
// :TODO: if username exists, record failed login attempt to properties
// :TODO: check Config max failed logon attempts/etc. - set err.maxAttempts = true

View File

@ -6,6 +6,7 @@ var MCIViewFactory = require('./mci_view_factory.js').MCIViewFactory;
var menuUtil = require('./menu_util.js');
var asset = require('./asset.js');
var ansi = require('./ansi_term.js');
const Log = require('./logger.js');
// deps
var events = require('events');
@ -328,7 +329,14 @@ function ViewController(options) {
}
}
self.client.log.trace( { formValue : formValue, actionValue : actionValue }, 'Action match');
self.client.log.trace(
{
formValue : formValue,
actionValue : actionValue
},
'Action match'
);
return true;
};

View File

@ -8,6 +8,7 @@ const ViewController = require('../core/view_controller.js').ViewController;
const ansi = require('../core/ansi_term.js');
const theme = require('../core/theme.js');
const getUserName = require('../core/user.js').getUserName;
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -99,7 +100,6 @@ function BBSListModule(options) {
self.setViewText(MciViewIds.view[mciName], '');
});
} else {
// :TODO: we really need pipe code support for TextView!!
const youSubmittedFormat = config.youSubmittedFormat || '{submitter} (You!)';
Object.keys(SELECTED_MCI_NAME_TO_ENTRY).forEach(mciName => {
@ -107,7 +107,7 @@ function BBSListModule(options) {
if(MciViewIds.view[mciName]) {
if('SelectedBBSSubmitter' == mciName && entry.submitterUserId == self.client.user.userId) {
self.setViewText(MciViewIds.view.SelectedBBSSubmitter, youSubmittedFormat.format(entry));
self.setViewText(MciViewIds.view.SelectedBBSSubmitter, stringFormat(youSubmittedFormat, entry));
} else {
self.setViewText(MciViewIds.view[mciName], t);
}
@ -120,8 +120,8 @@ function BBSListModule(options) {
const listFormat = config.listFormat || '{bbsName}';
const focusListFormat = config.focusListFormat || '{bbsName}';
entriesView.setItems(self.entries.map( e => listFormat.format(e) ) );
entriesView.setFocusItems(self.entries.map( e => focusListFormat.format(e) ) );
entriesView.setItems(self.entries.map( e => stringFormat(listFormat, e) ) );
entriesView.setFocusItems(self.entries.map( e => stringFormat(focusListFormat, e) ) );
};
this.displayBBSList = function(clearScreen, cb) {

View File

@ -2,6 +2,7 @@
'use strict';
var MenuModule = require('../core/menu_module.js').MenuModule;
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -86,10 +87,10 @@ function ErcClientModule(options) {
try {
if(data.userName) {
// user message
text = self.chatEntryFormat.format(data);
text = stringFormat(self.chatEntryFormat, data);
} else {
// system message
text = self.systemEntryFormat.format(data);
text = stringFormat(self.systemEntryFormat, data);
}
} catch(e) {
return self.client.log.warn( { error : e.message }, 'ERC: chatEntryFormat error');

View File

@ -8,6 +8,7 @@ const StatLog = require('../core/stat_log.js');
const getUserName = require('../core/user.js').getUserName;
const loadProperties = require('../core/user.js').loadProperties;
const isRootUserId = require('../core/user.js').isRootUserId;
const stringFormat = require('../core/string_format.js');
// deps
const moment = require('moment');
@ -123,12 +124,9 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) {
);
},
function populateList(callback) {
const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affils} - {ts}';
const listFormat = self.menuConfig.config.listFormat || '{userName} - {location} - {affiliation} - {ts}';
callersView.setItems(_.map(loginHistory, ce => listFormat.format(ce) ) );
// :TODO: This is a hack until pipe codes are better implemented
callersView.focusItems = callersView.items;
callersView.setItems(_.map(loginHistory, ce => stringFormat(listFormat, ce) ) );
callersView.redraw();
return callback(null);

View File

@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js');
const displayThemeArt = require('../core/theme.js').displayThemeArt;
const displayThemedPause = require('../core/theme.js').displayThemedPause;
const resetScreen = require('../core/ansi_term.js').resetScreen;
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -152,7 +153,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) {
const areaListView = vc.getView(MCICodesIDs.AreaList);
let i = 1;
areaListView.setItems(_.map(self.messageAreas, v => {
return listFormat.format({
return stringFormat(listFormat, {
index : i++,
areaTag : v.area.areaTag,
name : v.area.name,
@ -162,7 +163,7 @@ MessageAreaListModule.prototype.mciReady = function(mciData, cb) {
i = 1;
areaListView.setFocusItems(_.map(self.messageAreas, v => {
return focusListFormat.format({
return stringFormat(focusListFormat, {
index : i++,
areaTag : v.area.areaTag,
name : v.area.name,

View File

@ -122,4 +122,8 @@ AreaViewFSEModule.prototype.restoreSavedState = function(savedState) {
this.messageList = savedState.messageList;
this.messageIndex = savedState.messageIndex;
this.messageTotal = savedState.messageTotal;
};
};
AreaViewFSEModule.prototype.getMenuResult = function() {
return this.messageIndex;
};

View File

@ -8,6 +8,7 @@ const messageArea = require('../core/message_area.js');
const displayThemeArt = require('../core/theme.js').displayThemeArt;
const displayThemedPause = require('../core/theme.js').displayThemedPause;
const resetScreen = require('../core/ansi_term.js').resetScreen;
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -121,7 +122,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) {
const confListView = vc.getView(MCICodeIDs.ConfList);
let i = 1;
confListView.setItems(_.map(self.messageConfs, v => {
return listFormat.format({
return stringFormat(listFormat, {
index : i++,
confTag : v.conf.confTag,
name : v.conf.name,
@ -131,7 +132,7 @@ MessageConfListModule.prototype.mciReady = function(mciData, cb) {
i = 1;
confListView.setFocusItems(_.map(self.messageConfs, v => {
return focusListFormat.format({
return stringFormat(focusListFormat, {
index : i++,
confTag : v.conf.confTag,
name : v.conf.name,

View File

@ -5,6 +5,7 @@
const MenuModule = require('../core/menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController;
const messageArea = require('../core/message_area.js');
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -209,11 +210,11 @@ MessageListModule.prototype.mciReady = function(mciData, cb) {
// which items are requested (e.g. their format at least) *as-needed* vs trying to get the format for all of them at once
msgListView.setItems(_.map(self.messageList, listEntry => {
return listFormat.format(listEntry);
return stringFormat(listFormat, listEntry);
}));
msgListView.setFocusItems(_.map(self.messageList, listEntry => {
return focusListFormat.format(listEntry);
return stringFormat(focusListFormat, listEntry);
}));
msgListView.on('index update', function indexUpdated(idx) {

View File

@ -154,7 +154,6 @@ function OnelinerzModule(options) {
} );
}));
entriesView.focusItems = entriesView.items; // :TODO: this is a hack
entriesView.redraw();
return callback(null);

View File

@ -8,6 +8,7 @@ const theme = require('../core/theme.js');
const resetScreen = require('../core/ansi_term.js').resetScreen;
const StatLog = require('../core/stat_log.js');
const renderStringLength = require('../core/string_util.js').renderStringLength;
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -158,8 +159,8 @@ exports.getModule = class RumorzModule extends MenuModule {
const listFormat = config.listFormat || '{rumor}';
const focusListFormat = config.focusListFormat || listFormat;
entriesView.setItems(entries.map( e => listFormat.format( { rumor : e.log_value } ) ) );
entriesView.setFocusItems(entries.map(e => focusListFormat.format( { rumor : e.log_value } ) ) );
entriesView.setItems(entries.map( e => stringFormat(listFormat, { rumor : e.log_value } ) ) );
entriesView.setFocusItems(entries.map(e => stringFormat(focusListFormat, { rumor : e.log_value } ) ) );
entriesView.redraw();
return callback(null);

View File

@ -5,10 +5,10 @@ var MenuModule = require('../core/menu_module.js').MenuModule;
//var userDb = require('../core/database.js').dbs.user;
var getUserList = require('../core/user.js').getUserList;
var ViewController = require('../core/view_controller.js').ViewController;
const stringFormat = require('../core/string_format.js');
var moment = require('moment');
var async = require('async');
var assert = require('assert');
var _ = require('lodash');
/*
@ -92,11 +92,11 @@ UserListModule.prototype.mciReady = function(mciData, cb) {
}
userListView.setItems(_.map(userList, function formatUserEntry(ue) {
return listFormat.format(getUserFmtObj(ue));
return stringFormat(listFormat, getUserFmtObj(ue));
}));
userListView.setFocusItems(_.map(userList, function formatUserEntry(ue) {
return focusListFormat.format(getUserFmtObj(ue));
return stringFormat(focusListFormat, getUserFmtObj(ue));
}));
userListView.redraw();

View File

@ -5,6 +5,7 @@
const MenuModule = require('../core/menu_module.js').MenuModule;
const ViewController = require('../core/view_controller.js').ViewController;
const getActiveNodeList = require('../core/client_connections.js').getActiveNodeList;
const stringFormat = require('../core/string_format.js');
// deps
const async = require('async');
@ -63,7 +64,7 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
});
oe.userName = nonAuthUser;
}
return listFormat.format(oe);
return stringFormat(listFormat, oe);
}));
onlineListView.focusItems = onlineListView.items;

View File

@ -27,8 +27,7 @@
"node-uuid": "^1.4.7",
"ptyw.js": "^0.3.7",
"sqlite3": "^3.1.1",
"ssh2": "^0.4.13",
"string-format": "davidchambers/string-format#mini-language",
"ssh2": "^0.4.13",
"temp": "^0.8.3",
"inquirer" : "^1.1.0",
"fs-extra" : "0.26.x",