* Code cleanup and eslint since -- remove unused variables, clean up RegExs, so on...
This commit is contained in:
parent
a106050ba3
commit
ac1433e84b
|
@ -3,7 +3,9 @@
|
|||
|
||||
const miscUtil = require('./misc_util.js');
|
||||
const ansi = require('./ansi_term.js');
|
||||
const Log = require('./logger.js').log;
|
||||
|
||||
// deps
|
||||
const events = require('events');
|
||||
const util = require('util');
|
||||
const _ = require('lodash');
|
||||
|
@ -24,7 +26,7 @@ function ANSIEscapeParser(options) {
|
|||
this.graphicRendition = {};
|
||||
|
||||
this.parseState = {
|
||||
re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g,
|
||||
re : /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, // eslint-disable-line no-control-regex
|
||||
};
|
||||
|
||||
options = miscUtil.valueWithDefault(options, {
|
||||
|
@ -63,7 +65,7 @@ function ANSIEscapeParser(options) {
|
|||
delete self.savedPosition;
|
||||
|
||||
self.positionUpdated();
|
||||
// self.rowUpdated();
|
||||
// self.rowUpdated();
|
||||
};
|
||||
|
||||
self.clearScreen = function() {
|
||||
|
@ -71,7 +73,7 @@ function ANSIEscapeParser(options) {
|
|||
self.emit('clear screen');
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
self.rowUpdated = function() {
|
||||
self.emit('row update', self.row + self.scrollBack);
|
||||
};*/
|
||||
|
@ -142,17 +144,9 @@ function ANSIEscapeParser(options) {
|
|||
}
|
||||
}
|
||||
|
||||
function getProcessedMCI(mci) {
|
||||
if(self.mciReplaceChar.length > 0) {
|
||||
return ansi.getSGRFromGraphicRendition(self.graphicRendition, true) + new Array(mci.length + 1).join(self.mciReplaceChar);
|
||||
} else {
|
||||
return mci;
|
||||
}
|
||||
}
|
||||
|
||||
function parseMCI(buffer) {
|
||||
// :TODO: move this to "constants" seciton @ top
|
||||
var mciRe = /\%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Za-z,]+)\))*/g;
|
||||
var mciRe = /%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Za-z,]+)\))*/g;
|
||||
var pos = 0;
|
||||
var match;
|
||||
var mciCode;
|
||||
|
@ -197,16 +191,12 @@ function ANSIEscapeParser(options) {
|
|||
if(self.mciReplaceChar.length > 0) {
|
||||
const sgrCtrl = ansi.getSGRFromGraphicRendition(self.graphicRenditionForErase);
|
||||
|
||||
self.emit('control', sgrCtrl, 'm', sgrCtrl.slice(2).split(/[\;m]/).slice(0, 3));
|
||||
self.emit('control', sgrCtrl, 'm', sgrCtrl.slice(2).split(/[;m]/).slice(0, 3));
|
||||
|
||||
literal(new Array(match[0].length + 1).join(self.mciReplaceChar));
|
||||
} else {
|
||||
literal(match[0]);
|
||||
}
|
||||
|
||||
//literal(getProcessedMCI(match[0]));
|
||||
|
||||
//self.emit('chunk', getProcessedMCI(match[0]));
|
||||
}
|
||||
|
||||
} while(0 !== mciRe.lastIndex);
|
||||
|
@ -220,7 +210,7 @@ function ANSIEscapeParser(options) {
|
|||
self.parseState = {
|
||||
// ignore anything past EOF marker, if any
|
||||
buffer : input.split(String.fromCharCode(0x1a), 1)[0],
|
||||
re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g,
|
||||
re : /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsu])/g, // eslint-disable-line no-control-regex
|
||||
stop : false,
|
||||
};
|
||||
};
|
||||
|
@ -291,13 +281,13 @@ function ANSIEscapeParser(options) {
|
|||
}
|
||||
}
|
||||
|
||||
parseMCI(lastBit)
|
||||
parseMCI(lastBit);
|
||||
}
|
||||
|
||||
self.emit('complete');
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
self.parse = function(buffer, savedRe) {
|
||||
// :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc.
|
||||
// :TODO: move this to "constants" section @ top
|
||||
|
@ -448,7 +438,7 @@ function ANSIEscapeParser(options) {
|
|||
break;
|
||||
|
||||
default :
|
||||
console.log('Unknown attribute: ' + arg); // :TODO: Log properly
|
||||
Log.trace( { attribute : arg }, 'Unknown attribute while parsing ANSI');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,9 +108,11 @@ module.exports = class ArchiveUtil {
|
|||
return this.getArchiver(archType) ? true : false;
|
||||
}
|
||||
|
||||
// :TODO: implement me:
|
||||
/*
|
||||
detectTypeWithBuf(buf, cb) {
|
||||
// :TODO: implement me!
|
||||
}
|
||||
*/
|
||||
|
||||
detectType(path, cb) {
|
||||
fs.open(path, 'r', (err, fd) => {
|
||||
|
|
|
@ -52,8 +52,8 @@ exports.Client = Client;
|
|||
// Resources & Standards:
|
||||
// * http://www.ansi-bbs.org/ansi-bbs-core-server.html
|
||||
//
|
||||
const RE_DSR_RESPONSE_ANYWHERE = /(?:\u001b\[)([0-9\;]+)(R)/;
|
||||
const RE_DEV_ATTR_RESPONSE_ANYWHERE = /(?:\u001b\[)[\=\?]([0-9a-zA-Z\;]+)(c)/;
|
||||
const RE_DSR_RESPONSE_ANYWHERE = /(?:\u001b\[)([0-9;]+)(R)/;
|
||||
const RE_DEV_ATTR_RESPONSE_ANYWHERE = /(?:\u001b\[)[=?]([0-9a-zA-Z;]+)(c)/;
|
||||
const RE_META_KEYCODE_ANYWHERE = /(?:\u001b)([a-zA-Z0-9])/;
|
||||
const RE_META_KEYCODE = new RegExp('^' + RE_META_KEYCODE_ANYWHERE.source + '$');
|
||||
const RE_FUNCTION_KEYCODE_ANYWHERE = new RegExp('(?:\u001b+)(O|N|\\[|\\[\\[)(?:' + [
|
||||
|
@ -72,7 +72,7 @@ const RE_ESC_CODE_ANYWHERE = new RegExp( [
|
|||
].join('|'));
|
||||
|
||||
|
||||
function Client(input, output) {
|
||||
function Client(/*input, output*/) {
|
||||
stream.call(this);
|
||||
|
||||
const self = this;
|
||||
|
@ -139,8 +139,8 @@ function Client(input, output) {
|
|||
};
|
||||
|
||||
this.isMouseInput = function(data) {
|
||||
return /\x1b\[M/.test(data) ||
|
||||
/\u001b\[M([\x00\u0020-\uffff]{3})/.test(data) ||
|
||||
return /\x1b\[M/.test(data) || // eslint-disable-line no-control-regex
|
||||
/\u001b\[M([\x00\u0020-\uffff]{3})/.test(data) || // eslint-disable-line no-control-regex
|
||||
/\u001b\[(\d+;\d+;\d+)M/.test(data) ||
|
||||
/\u001b\[<(\d+;\d+;\d+)([mM])/.test(data) ||
|
||||
/\u001b\[<(\d+;\d+;\d+;\d+)&w/.test(data) ||
|
||||
|
@ -482,7 +482,7 @@ Client.prototype.isLocal = function() {
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// :TODO: getDefaultHandler(name) -- handlers in default_handlers.js or something
|
||||
Client.prototype.defaultHandlerMissingMod = function(err) {
|
||||
Client.prototype.defaultHandlerMissingMod = function() {
|
||||
var self = this;
|
||||
|
||||
function handler(err) {
|
||||
|
|
|
@ -95,7 +95,7 @@ function removeClient(client) {
|
|||
clientId : client.session.id
|
||||
},
|
||||
'Client disconnected'
|
||||
);
|
||||
);
|
||||
|
||||
Events.emit('codes.l33t.enigma.system.disconnected', { client : client, connectionCount : clientConnections.length } );
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@ exports.ClientTerminal = ClientTerminal;
|
|||
function ClientTerminal(output) {
|
||||
this.output = output;
|
||||
|
||||
var self = this;
|
||||
|
||||
var outputEncoding = 'cp437';
|
||||
assert(iconv.encodingExists(outputEncoding));
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ function renegadeToAnsi(s, client) {
|
|||
// * http://wiki.synchro.net/custom:colors
|
||||
//
|
||||
function controlCodesToAnsi(s, client) {
|
||||
const RE = /(\|([A-Z0-9]{2})|\|)|(\@X([0-9A-F]{2}))|(\@([0-9A-F]{2})\@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex
|
||||
const RE = /(\|([A-Z0-9]{2})|\|)|(@X([0-9A-F]{2}))|(@([0-9A-F]{2})@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex
|
||||
|
||||
let m;
|
||||
let result = '';
|
||||
|
|
|
@ -45,59 +45,59 @@ exports.getModule = class CombatNetModule extends MenuModule {
|
|||
self.client.term.write('Connecting to CombatNet, please wait...\n');
|
||||
|
||||
const restorePipeToNormal = function() {
|
||||
self.client.term.output.removeListener('data', sendToRloginBuffer);
|
||||
self.client.term.output.removeListener('data', sendToRloginBuffer);
|
||||
};
|
||||
|
||||
const rlogin = new RLogin(
|
||||
{ 'clientUsername' : self.config.password,
|
||||
'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`,
|
||||
'host' : self.config.host,
|
||||
'port' : self.config.rloginPort,
|
||||
'terminalType' : self.client.term.termClient,
|
||||
'terminalSpeed' : 57600
|
||||
}
|
||||
);
|
||||
const rlogin = new RLogin(
|
||||
{ 'clientUsername' : self.config.password,
|
||||
'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`,
|
||||
'host' : self.config.host,
|
||||
'port' : self.config.rloginPort,
|
||||
'terminalType' : self.client.term.termClient,
|
||||
'terminalSpeed' : 57600
|
||||
}
|
||||
);
|
||||
|
||||
// If there was an error ...
|
||||
rlogin.on('error', err => {
|
||||
self.client.log.info(`CombatNet rlogin client error: ${err.message}`);
|
||||
restorePipeToNormal();
|
||||
callback(err);
|
||||
});
|
||||
// If there was an error ...
|
||||
rlogin.on('error', err => {
|
||||
self.client.log.info(`CombatNet rlogin client error: ${err.message}`);
|
||||
restorePipeToNormal();
|
||||
return callback(err);
|
||||
});
|
||||
|
||||
// If we've been disconnected ...
|
||||
rlogin.on('disconnect', () => {
|
||||
self.client.log.info(`Disconnected from CombatNet`);
|
||||
restorePipeToNormal();
|
||||
callback(null);
|
||||
});
|
||||
// If we've been disconnected ...
|
||||
rlogin.on('disconnect', () => {
|
||||
self.client.log.info('Disconnected from CombatNet');
|
||||
restorePipeToNormal();
|
||||
return callback(null);
|
||||
});
|
||||
|
||||
function sendToRloginBuffer(buffer) {
|
||||
rlogin.send(buffer);
|
||||
};
|
||||
function sendToRloginBuffer(buffer) {
|
||||
rlogin.send(buffer);
|
||||
}
|
||||
|
||||
rlogin.on("connect",
|
||||
/* The 'connect' event handler will be supplied with one argument,
|
||||
rlogin.on('connect',
|
||||
/* The 'connect' event handler will be supplied with one argument,
|
||||
a boolean indicating whether or not the connection was established. */
|
||||
|
||||
function(state) {
|
||||
if(state) {
|
||||
self.client.log.info('Connected to CombatNet');
|
||||
self.client.term.output.on('data', sendToRloginBuffer);
|
||||
function(state) {
|
||||
if(state) {
|
||||
self.client.log.info('Connected to CombatNet');
|
||||
self.client.term.output.on('data', sendToRloginBuffer);
|
||||
|
||||
} else {
|
||||
return callback(new Error('Failed to establish establish CombatNet connection'));
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return callback(new Error('Failed to establish establish CombatNet connection'));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// If data (a Buffer) has been received from the server ...
|
||||
rlogin.on("data", (data) => {
|
||||
self.client.term.rawWrite(data);
|
||||
});
|
||||
// If data (a Buffer) has been received from the server ...
|
||||
rlogin.on('data', (data) => {
|
||||
self.client.term.rawWrite(data);
|
||||
});
|
||||
|
||||
// connect...
|
||||
rlogin.connect();
|
||||
// connect...
|
||||
rlogin.connect();
|
||||
|
||||
// note: no explicit callback() until we're finished!
|
||||
}
|
||||
|
|
|
@ -653,12 +653,12 @@ function getDefaultConfig() {
|
|||
// FILE_ID.DIZ - https://en.wikipedia.org/wiki/FILE_ID.DIZ
|
||||
// Some groups include a FILE_ID.ANS. We try to use that over FILE_ID.DIZ if available.
|
||||
desc : [
|
||||
'^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$'
|
||||
'^[^/\]*FILE_ID\.ANS$', '^[^/\]*FILE_ID\.DIZ$', '^[^/\]*DESC\.SDI$', '^[^/\]*DESCRIPT\.ION$', '^[^/\]*FILE\.DES$', '^[^/\]*FILE\.SDI$', '^[^/\]*DISK\.ID$' // eslint-disable-line no-useless-escape
|
||||
],
|
||||
|
||||
// common README filename - https://en.wikipedia.org/wiki/README
|
||||
descLong : [
|
||||
'^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$'
|
||||
'^[^/\]*\.NFO$', '^[^/\]*README\.1ST$', '^[^/\]*README\.NOW$', '^[^/\]*README\.TXT$', '^[^/\]*READ\.ME$', '^[^/\]*README$', '^[^/\]*README\.md$' // eslint-disable-line no-useless-escape
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ util.inherits(ConfigCache, events.EventEmitter);
|
|||
ConfigCache.prototype.getConfigWithOptions = function(options, cb) {
|
||||
assert(_.isString(options.filePath));
|
||||
|
||||
// var self = this;
|
||||
// var self = this;
|
||||
var isCached = (options.filePath in this.cache);
|
||||
|
||||
if(options.forceReCache || !isCached) {
|
||||
|
|
|
@ -98,7 +98,7 @@ function ansiQueryTermSizeIfNeeded(client, cb) {
|
|||
source : 'ANSI CPR'
|
||||
},
|
||||
'Window size updated'
|
||||
);
|
||||
);
|
||||
|
||||
return done(null);
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ function getModDatabasePath(moduleInfo, suffix) {
|
|||
// We expect that moduleInfo defines packageName which will be the base of the modules
|
||||
// filename. An optional suffix may be supplied as well.
|
||||
//
|
||||
const HOST_RE = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
|
||||
const HOST_RE = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/;
|
||||
|
||||
assert(_.isObject(moduleInfo));
|
||||
assert(_.isString(moduleInfo.packageName), 'moduleInfo must define "packageName"!');
|
||||
|
|
|
@ -24,8 +24,8 @@ exports.moduleInfo = {
|
|||
author : 'NuSkooler',
|
||||
};
|
||||
|
||||
const SCHEDULE_REGEXP = /(?:^|or )?(@watch\:)([^\0]+)?$/;
|
||||
const ACTION_REGEXP = /\@(method|execute)\:([^\0]+)?$/;
|
||||
const SCHEDULE_REGEXP = /(?:^|or )?(@watch:)([^\0]+)?$/;
|
||||
const ACTION_REGEXP = /@(method|execute):([^\0]+)?$/;
|
||||
|
||||
class ScheduledEvent {
|
||||
constructor(events, name) {
|
||||
|
|
|
@ -586,10 +586,6 @@ function addNewFileEntry(fileEntry, filePath, cb) {
|
|||
);
|
||||
}
|
||||
|
||||
function updateFileEntry(fileEntry, filePath, cb) {
|
||||
|
||||
}
|
||||
|
||||
const HASH_NAMES = [ 'sha1', 'sha256', 'md5', 'crc32' ];
|
||||
|
||||
function scanFile(filePath, options, iterator, cb) {
|
||||
|
@ -747,7 +743,9 @@ function scanFile(filePath, options, iterator, cb) {
|
|||
populateFileEntryWithArchive(fileEntry, filePath, stepInfo, callIter, err => {
|
||||
if(err) {
|
||||
populateFileEntryNonArchive(fileEntry, filePath, stepInfo, callIter, err => {
|
||||
// :TODO: log err
|
||||
if(err) {
|
||||
logDebug( { error : err.message }, 'Non-archive file entry population failed');
|
||||
}
|
||||
return callback(null); // ignore err
|
||||
});
|
||||
} else {
|
||||
|
@ -756,7 +754,9 @@ function scanFile(filePath, options, iterator, cb) {
|
|||
});
|
||||
} else {
|
||||
populateFileEntryNonArchive(fileEntry, filePath, stepInfo, callIter, err => {
|
||||
// :TODO: log err
|
||||
if(err) {
|
||||
logDebug( { error : err.message }, 'Non-archive file entry population failed');
|
||||
}
|
||||
return callback(null); // ignore err
|
||||
});
|
||||
}
|
||||
|
@ -874,7 +874,7 @@ function getDescFromFileName(fileName) {
|
|||
const ext = paths.extname(fileName);
|
||||
const name = paths.basename(fileName, ext);
|
||||
|
||||
return _.upperFirst(name.replace(/[\-_.+]/g, ' ').replace(/\s+/g, ' '));
|
||||
return _.upperFirst(name.replace(/[-_.+]/g, ' ').replace(/\s+/g, ' '));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -59,8 +59,6 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule {
|
|||
|
||||
return this.gotoMenu(this.menuConfig.config.fileTransferProtocolSelection || 'fileTransferProtocolSelection', modOpts, cb);
|
||||
},
|
||||
viewItemInfo : (formData, extraArgs, cb) => {
|
||||
},
|
||||
removeItem : (formData, extraArgs, cb) => {
|
||||
const selectedItem = this.dlQueue.items[formData.value.queueItem];
|
||||
if(!selectedItem) {
|
||||
|
|
|
@ -94,7 +94,7 @@ module.exports = class FileBaseFilters {
|
|||
}
|
||||
|
||||
cleanTags(tags) {
|
||||
return tags.toLowerCase().replace(/,?\s+|\,/g, ' ').trim();
|
||||
return tags.toLowerCase().replace(/,?\s+|,/g, ' ').trim();
|
||||
}
|
||||
|
||||
setActive(filterUuid) {
|
||||
|
|
|
@ -284,4 +284,3 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule {
|
|||
);
|
||||
}
|
||||
};
|
||||
|
|
@ -46,5 +46,5 @@ module.exports = class FNV1a {
|
|||
get value() {
|
||||
return this.hash & 0xffffffff;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
46
core/fse.js
46
core/fse.js
|
@ -179,26 +179,24 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
|||
|
||||
self.switchFooter(function next(err) {
|
||||
if(err) {
|
||||
// :TODO:... what now?
|
||||
console.log(err)
|
||||
} else {
|
||||
switch(self.footerMode) {
|
||||
case 'editor' :
|
||||
if(!_.isUndefined(self.viewControllers.footerEditorMenu)) {
|
||||
//self.viewControllers.footerEditorMenu.setFocus(false);
|
||||
self.viewControllers.footerEditorMenu.detachClientEvents();
|
||||
}
|
||||
self.viewControllers.body.switchFocus(1);
|
||||
self.observeEditorEvents();
|
||||
break;
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
case 'editorMenu' :
|
||||
self.viewControllers.body.setFocus(false);
|
||||
self.viewControllers.footerEditorMenu.switchFocus(1);
|
||||
break;
|
||||
switch(self.footerMode) {
|
||||
case 'editor' :
|
||||
if(!_.isUndefined(self.viewControllers.footerEditorMenu)) {
|
||||
self.viewControllers.footerEditorMenu.detachClientEvents();
|
||||
}
|
||||
self.viewControllers.body.switchFocus(1);
|
||||
self.observeEditorEvents();
|
||||
break;
|
||||
|
||||
default : throw new Error('Unexpected mode');
|
||||
}
|
||||
case 'editorMenu' :
|
||||
self.viewControllers.body.setFocus(false);
|
||||
self.viewControllers.footerEditorMenu.switchFocus(1);
|
||||
break;
|
||||
|
||||
default : throw new Error('Unexpected mode');
|
||||
}
|
||||
|
||||
return cb(null);
|
||||
|
@ -534,7 +532,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
|||
art[n],
|
||||
self.client,
|
||||
{ font : self.menuConfig.font },
|
||||
function displayed(err, artData) {
|
||||
function displayed(err) {
|
||||
next(err);
|
||||
}
|
||||
);
|
||||
|
@ -645,8 +643,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
|||
],
|
||||
function complete(err) {
|
||||
if(err) {
|
||||
// :TODO: This needs properly handled!
|
||||
console.log(err)
|
||||
self.client.log.warn( { error : err.message }, 'FSE init error');
|
||||
} else {
|
||||
self.isReady = true;
|
||||
self.finishedLoading();
|
||||
|
@ -763,10 +760,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
|||
}
|
||||
],
|
||||
function complete(err) {
|
||||
if(err) {
|
||||
console.error(err)
|
||||
}
|
||||
cb(err);
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -954,7 +948,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
|||
],
|
||||
function complete(err) {
|
||||
if(err) {
|
||||
console.log(err) // :TODO: needs real impl.
|
||||
self.client.log.warn( { error : err.message }, 'Error displaying quote builder');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
const _ = require('lodash');
|
||||
|
||||
const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-\.]+)?$/i;
|
||||
const FTN_PATTERN_REGEXP = /^([0-9\*]+:)?([0-9\*]+)(\/[0-9\*]+)?(\.[0-9\*]+)?(@[a-z0-9\-\.\*]+)?$/i;
|
||||
const FTN_ADDRESS_REGEXP = /^([0-9]+:)?([0-9]+)(\/[0-9]+)?(\.[0-9]+)?(@[a-z0-9\-.]+)?$/i;
|
||||
const FTN_PATTERN_REGEXP = /^([0-9*]+:)?([0-9*]+)(\/[0-9*]+)?(\.[0-9*]+)?(@[a-z0-9\-.*]+)?$/i;
|
||||
|
||||
module.exports = class Address {
|
||||
constructor(addr) {
|
||||
|
|
|
@ -426,12 +426,12 @@ function Packet(options) {
|
|||
if(!err) {
|
||||
// we read some SAUCE - don't re-process that portion into the body
|
||||
messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition) + messageBodyBuffer.slice(sauceHeaderPosition + sauce.SAUCE_SIZE);
|
||||
// messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition);
|
||||
// messageBodyBuffer = messageBodyBuffer.slice(0, sauceHeaderPosition);
|
||||
messageBodyData.sauce = theSauce;
|
||||
} else {
|
||||
console.log(err)
|
||||
Log.warn( { error : err.message }, 'Found what looks like to be a SAUCE record, but failed to read');
|
||||
}
|
||||
callback(null); // failure to read SAUCE is OK
|
||||
return callback(null); // failure to read SAUCE is OK
|
||||
});
|
||||
} else {
|
||||
callback(null);
|
||||
|
@ -497,7 +497,7 @@ function Packet(options) {
|
|||
} else if(line.startsWith('--- ')) {
|
||||
// Tear Lines are tracked allowing for specialized display/etc.
|
||||
messageBodyData.tearLine = line;
|
||||
} else if(/^[ ]{1,2}\* Origin\: /.test(line)) { // To spec is " * Origin: ..."
|
||||
} else if(/^[ ]{1,2}\* Origin: /.test(line)) { // To spec is " * Origin: ..."
|
||||
messageBodyData.originLine = line;
|
||||
endOfMessage = true; // Anything past origin is not part of the message body
|
||||
} else if(line.startsWith('SEEN-BY:')) {
|
||||
|
@ -1040,6 +1040,6 @@ Packet.prototype.write = function(path, packetHeader, messages, options) {
|
|||
this.writeStream(
|
||||
fs.createWriteStream(path), // :TODO: specify mode/etc.
|
||||
messages,
|
||||
{ packetHeader : packetHeader, terminatePacket : true }
|
||||
);
|
||||
Object.assign( { packetHeader : packetHeader, terminatePacket : true }, options)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -148,7 +148,7 @@ function getMessageIdentifier(message, address, isNetMail = false) {
|
|||
return isNetMail ?
|
||||
`${addrStr} ${getMessageSerialNumber(message.messageId)}` :
|
||||
`${message.messageId}.${message.areaTag.toLowerCase()}@${addrStr} ${getMessageSerialNumber(message.messageId)}`
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -225,11 +225,7 @@ function getVia(address) {
|
|||
*/
|
||||
const addrStr = new Address(address).toString('5D');
|
||||
const dateTime = moment().utc().format('YYYYMMDD.HHmmSS.SSSS.UTC');
|
||||
|
||||
const version = packageJson.version
|
||||
.replace(/\-/g, '.')
|
||||
.replace(/alpha/,'a')
|
||||
.replace(/beta/,'b');
|
||||
const version = getCleanEnigmaVersion();
|
||||
|
||||
return `${addrStr} @${dateTime} ENiGMA1/2 ${version}`;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ function HorizontalMenuView(options) {
|
|||
ansi.goto(self.position.row, item.col) +
|
||||
(index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR()) +
|
||||
strUtil.pad(text, drawWidth, self.fillChar, 'center')
|
||||
);
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,4 +33,4 @@ MailPacket.prototype.write = function(options) {
|
|||
// emits 'packet' event per packet constructed
|
||||
//
|
||||
assert(_.isArray(options.messages));
|
||||
}
|
||||
};
|
|
@ -6,7 +6,7 @@ const Message = require('./message.js');
|
|||
|
||||
exports.getAddressedToInfo = getAddressedToInfo;
|
||||
|
||||
const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
|
||||
/*
|
||||
Input Output
|
||||
|
|
|
@ -4,13 +4,12 @@
|
|||
// ENiGMA½
|
||||
const TextView = require('./text_view.js').TextView;
|
||||
const EditTextView = require('./edit_text_view.js').EditTextView;
|
||||
const ButtonView = require('./button_view.js').ButtonView;
|
||||
const ButtonView = require('./button_view.js').ButtonView;
|
||||
const VerticalMenuView = require('./vertical_menu_view.js').VerticalMenuView;
|
||||
const HorizontalMenuView = require('./horizontal_menu_view.js').HorizontalMenuView;
|
||||
const SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView;
|
||||
const ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView;
|
||||
const HorizontalMenuView = require('./horizontal_menu_view.js').HorizontalMenuView;
|
||||
const SpinnerMenuView = require('./spinner_menu_view.js').SpinnerMenuView;
|
||||
const ToggleMenuView = require('./toggle_menu_view.js').ToggleMenuView;
|
||||
const MaskEditTextView = require('./mask_edit_text_view.js').MaskEditTextView;
|
||||
//const StatusBarView = require('./status_bar_view.js').StatusBarView;
|
||||
const KeyEntryView = require('./key_entry_view.js');
|
||||
const MultiLineEditTextView = require('./multi_line_edit_text_view.js').MultiLineEditTextView;
|
||||
const getPredefinedMCIValue = require('./predefined_mci.js').getPredefinedMCIValue;
|
||||
|
@ -37,7 +36,7 @@ MCIViewFactory.UserViewCodes = [
|
|||
'XY',
|
||||
];
|
||||
|
||||
MCIViewFactory.prototype.createFromMCI = function(mci, cb) {
|
||||
MCIViewFactory.prototype.createFromMCI = function(mci) {
|
||||
assert(mci.code);
|
||||
assert(mci.id > 0);
|
||||
assert(mci.position);
|
||||
|
|
|
@ -548,7 +548,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
|
|||
quoteLines.push(`${lastSgr}${l}`);
|
||||
|
||||
focusQuoteLines.push(`${options.ansiFocusPrefixSgr}>${lastSgr}${renderSubstr(l, 1, l.length - 1)}`);
|
||||
lastSgr = (l.match(/(?:\x1b\x5b)[\?=;0-9]*m(?!.*(?:\x1b\x5b)[\?=;0-9]*m)/) || [])[0] || ''; // eslint-disable-line no-control-regex
|
||||
lastSgr = (l.match(/(?:\x1b\x5b)[?=;0-9]*m(?!.*(?:\x1b\x5b)[?=;0-9]*m)/) || [])[0] || ''; // eslint-disable-line no-control-regex
|
||||
});
|
||||
|
||||
quoteLines[quoteLines.length - 1] += options.ansiResetSgr;
|
||||
|
@ -557,7 +557,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
|
|||
}
|
||||
);
|
||||
} else {
|
||||
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}\> )+(?:[A-Za-z0-9]{2}\>)*) */;
|
||||
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}> )+(?:[A-Za-z0-9]{2}>)*) */;
|
||||
const quoted = [];
|
||||
const input = _.trimEnd(this.message).replace(/\b/g, '');
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ function getAvailableMessageConferences(client, options) {
|
|||
|
||||
assert(client || true === options.noClient);
|
||||
|
||||
// perform ACS check per conf & omit system_internal if desired
|
||||
// perform ACS check per conf & omit system_internal if desired
|
||||
return _.omitBy(Config.messageConferences, (conf, confTag) => {
|
||||
if(!options.includeSystemInternal && 'system_internal' === confTag) {
|
||||
return true;
|
||||
|
@ -68,7 +68,7 @@ function getSortedAvailMessageConferences(client, options) {
|
|||
function getAvailableMessageAreasByConfTag(confTag, options) {
|
||||
options = options || {};
|
||||
|
||||
// :TODO: confTag === "" then find default
|
||||
// :TODO: confTag === "" then find default
|
||||
|
||||
if(_.has(Config.messageConferences, [ confTag, 'areas' ])) {
|
||||
const areas = Config.messageConferences[confTag].areas;
|
||||
|
@ -159,18 +159,6 @@ function getMessageConferenceByTag(confTag) {
|
|||
return Config.messageConferences[confTag];
|
||||
}
|
||||
|
||||
function getMessageConfByAreaTag(areaTag) {
|
||||
const confs = Config.messageConferences;
|
||||
let conf;
|
||||
_.forEach(confs, (v) => {
|
||||
if(_.has(v, [ 'areas', areaTag ])) {
|
||||
conf = v;
|
||||
return false; // stop iteration
|
||||
}
|
||||
});
|
||||
return conf;
|
||||
}
|
||||
|
||||
function getMessageConfTagByAreaTag(areaTag) {
|
||||
const confs = Config.messageConferences;
|
||||
return Object.keys(confs).find( (confTag) => {
|
||||
|
@ -261,9 +249,9 @@ function changeMessageAreaWithOptions(client, areaTag, options, cb) {
|
|||
return callback(area ? null : new Error('Invalid message areaTag'), area);
|
||||
},
|
||||
function validateAccess(area, callback) {
|
||||
//
|
||||
// Need at least *read* to access the area
|
||||
//
|
||||
//
|
||||
// Need at least *read* to access the area
|
||||
//
|
||||
if(!client.acs.hasMessageAreaRead(area)) {
|
||||
return callback(new Error('Access denied to message area'));
|
||||
} else {
|
||||
|
|
|
@ -36,10 +36,10 @@ function resolvePath(path) {
|
|||
|
||||
function getCleanEnigmaVersion() {
|
||||
return packageJson.version
|
||||
.replace(/\-/g, '.')
|
||||
.replace(/-/g, '.')
|
||||
.replace(/alpha/,'a')
|
||||
.replace(/beta/,'b')
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
// See also ftn_util.js getTearLine() & getProductIdentifier()
|
||||
|
|
|
@ -98,9 +98,9 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
|
|||
}, timeout);
|
||||
}
|
||||
|
||||
// :TODO: these concepts have been replaced with the {someKey} style formatting - update me!
|
||||
/*
|
||||
updateGeneralAreaInfoViews(areaIndex) {
|
||||
// :TODO: these concepts have been replaced with the {someKey} style formatting - update me!
|
||||
/* experimental: not yet avail
|
||||
const areaInfo = self.messageAreas[areaIndex];
|
||||
|
||||
[ MciViewIds.SelAreaInfo1, MciViewIds.SelAreaInfo2 ].forEach(mciId => {
|
||||
|
@ -109,8 +109,8 @@ exports.getModule = class MessageAreaListModule extends MenuModule {
|
|||
v.setFormatObject(areaInfo.area);
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
||||
mciReady(mciData, cb) {
|
||||
super.mciReady(mciData, err => {
|
||||
|
|
|
@ -48,7 +48,7 @@ exports.getModule = class AreaPostFSEModule extends FullScreenEditorModule {
|
|||
self.client.log.info(
|
||||
{ to : msg.toUserName, subject : msg.subject, uuid : msg.uuid },
|
||||
'Message persisted'
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
return self.nextMenu(cb);
|
||||
|
|
|
@ -13,12 +13,12 @@ function MessageScanTossModule() {
|
|||
require('util').inherits(MessageScanTossModule, PluginModule);
|
||||
|
||||
MessageScanTossModule.prototype.startup = function(cb) {
|
||||
cb(null);
|
||||
return cb(null);
|
||||
};
|
||||
|
||||
MessageScanTossModule.prototype.shutdown = function(cb) {
|
||||
cb(null);
|
||||
return cb(null);
|
||||
};
|
||||
|
||||
MessageScanTossModule.prototype.record = function(message) {
|
||||
MessageScanTossModule.prototype.record = function(/*message*/) {
|
||||
};
|
|
@ -4,7 +4,6 @@
|
|||
const View = require('./view.js').View;
|
||||
const strUtil = require('./string_util.js');
|
||||
const ansi = require('./ansi_term.js');
|
||||
const colorCodes = require('./color_codes.js');
|
||||
const wordWrapText = require('./word_wrap.js').wordWrapText;
|
||||
const ansiPrep = require('./ansi_prep.js');
|
||||
|
||||
|
@ -12,11 +11,11 @@ const assert = require('assert');
|
|||
const _ = require('lodash');
|
||||
|
||||
// :TODO: Determine CTRL-* keys for various things
|
||||
// See http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
|
||||
// http://wiki.synchro.net/howto:editor:slyedit#edit_mode
|
||||
// http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/keyboard_shortcuts_win.html
|
||||
// See http://www.bbsdocumentary.com/library/PROGRAMS/GRAPHICS/ANSI/bansi.txt
|
||||
// http://wiki.synchro.net/howto:editor:slyedit#edit_mode
|
||||
// http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/keyboard_shortcuts_win.html
|
||||
|
||||
/* Mystic
|
||||
/* Mystic
|
||||
[^B] Reformat Paragraph [^O] Show this help file
|
||||
[^I] Insert tab space [^Q] Enter quote mode
|
||||
[^K] Cut current line of text [^V] Toggle insert/overwrite
|
||||
|
@ -268,7 +267,7 @@ function MultiLineEditTextView(options) {
|
|||
|
||||
if(remain > 0) {
|
||||
text += ' '.repeat(remain + 1);
|
||||
// text += new Array(remain + 1).join(' ');
|
||||
// text += new Array(remain + 1).join(' ');
|
||||
}
|
||||
|
||||
return text;
|
||||
|
@ -459,7 +458,7 @@ function MultiLineEditTextView(options) {
|
|||
self.getRenderText(index).slice(self.cursorPos.col - c.length) +
|
||||
ansi.goto(absPos.row, absPos.col) +
|
||||
ansi.showCursor(), false
|
||||
);
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ exports.getModule = class NewScanModule extends MenuModule {
|
|||
}
|
||||
|
||||
newScanMessageConference(cb) {
|
||||
// lazy init
|
||||
// lazy init
|
||||
if(!this.sortedMessageConfs) {
|
||||
const getAvailOpts = { includeSystemInternal : true }; // find new private messages, bulletins, etc.
|
||||
|
||||
|
@ -108,7 +108,7 @@ exports.getModule = class NewScanModule extends MenuModule {
|
|||
}
|
||||
|
||||
newScanMessageArea(conf, cb) {
|
||||
// :TODO: it would be nice to cache this - must be done by conf!
|
||||
// :TODO: it would be nice to cache this - must be done by conf!
|
||||
const sortedAreas = msgArea.getSortedAvailMessageAreasByConfTag(conf.confTag, { client : this.client } );
|
||||
const currentArea = sortedAreas[this.currentScanAux.area];
|
||||
|
||||
|
|
|
@ -284,10 +284,10 @@ exports.getModule = class OnelinerzModule extends MenuModule {
|
|||
oneliner VARCHAR NOT NULL,
|
||||
timestamp DATETIME NOT NULL
|
||||
);`
|
||||
,
|
||||
err => {
|
||||
return callback(err);
|
||||
});
|
||||
,
|
||||
err => {
|
||||
return callback(err);
|
||||
});
|
||||
}
|
||||
],
|
||||
err => {
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
|
||||
exports.PluginModule = PluginModule;
|
||||
|
||||
function PluginModule(options) {
|
||||
function PluginModule(/*options*/) {
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ exports.readSAUCE = readSAUCE;
|
|||
|
||||
const SAUCE_SIZE = 128;
|
||||
const SAUCE_ID = new Buffer([0x53, 0x41, 0x55, 0x43, 0x45]); // 'SAUCE'
|
||||
const COMNT_ID = new Buffer([0x43, 0x4f, 0x4d, 0x4e, 0x54]); // 'COMNT'
|
||||
|
||||
// :TODO read comments
|
||||
//const COMNT_ID = new Buffer([0x43, 0x4f, 0x4d, 0x4e, 0x54]); // 'COMNT'
|
||||
|
||||
exports.SAUCE_SIZE = SAUCE_SIZE;
|
||||
// :TODO: SAUCE should be a class
|
||||
|
@ -137,7 +139,7 @@ var SAUCE_FONT_TO_ENCODING_HINT = {
|
|||
};
|
||||
|
||||
['437', '720', '737', '775', '819', '850', '852', '855', '857', '858',
|
||||
'860', '861', '862', '863', '864', '865', '866', '869', '872'].forEach(function onPage(page) {
|
||||
'860', '861', '862', '863', '864', '865', '866', '869', '872'].forEach(function onPage(page) {
|
||||
var codec = 'cp' + page;
|
||||
SAUCE_FONT_TO_ENCODING_HINT['IBM EGA43 ' + page] = codec;
|
||||
SAUCE_FONT_TO_ENCODING_HINT['IBM EGA ' + page] = codec;
|
||||
|
|
|
@ -1213,7 +1213,30 @@ function FTNMessageScanTossModule() {
|
|||
|
||||
User.getUserIdAndNameByLookup(lookupName, (err, localToUserId, localUserName) => {
|
||||
if(err) {
|
||||
return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`));
|
||||
//
|
||||
// Couldn't find a local username. If the toUserName itself is a FTN address
|
||||
// we can only assume the message is to the +op, else we'll have to fail.
|
||||
//
|
||||
const toUserNameAsAddress = Address.fromString(message.toUserName);
|
||||
if(toUserNameAsAddress.isValid()) {
|
||||
|
||||
Log.info(
|
||||
{ toUserName : message.toUserName, fromUserName : message.fromUserName },
|
||||
'No local "to" username for FTN message. Appears to be a FTN address only; assuming addressed to SysOp'
|
||||
);
|
||||
|
||||
User.getUserName(User.RootUserID, (err, sysOpUserName) => {
|
||||
if(err) {
|
||||
return callback(Errors.UnexpectedState('Failed to get SysOp user information'));
|
||||
}
|
||||
|
||||
message.meta.System[Message.SystemMetaNames.LocalToUserID] = User.RootUserID;
|
||||
message.toUserName = sysOpUserName;
|
||||
return callback(null);
|
||||
});
|
||||
} else {
|
||||
return callback(Errors.DoesNotExist(`Could not get local user ID for "${message.toUserName}": ${err.message}`));
|
||||
}
|
||||
}
|
||||
|
||||
// we do this after such that error cases can be preseved above
|
||||
|
|
|
@ -232,7 +232,7 @@ exports.getModule = class SetNewScanDate extends MenuModule {
|
|||
const scanDateView = vc.getView(MciViewIds.main.scanDate);
|
||||
|
||||
// :TODO: MaskTextEditView needs some love: If setText() with input that matches the mask, we should ignore the non-mask chars! Hack in place for now
|
||||
const scanDateFormat = self.scanDateFormat.replace(/[\/\-. ]/g, '');
|
||||
const scanDateFormat = self.scanDateFormat.replace(/[/\-. ]/g, '');
|
||||
scanDateView.setText(today.format(scanDateFormat));
|
||||
|
||||
if('message' === self.target) {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var MenuView = require('./menu_view.js').MenuView;
|
||||
var ansi = require('./ansi_term.js');
|
||||
var strUtil = require('./string_util.js');
|
||||
const MenuView = require('./menu_view.js').MenuView;
|
||||
const ansi = require('./ansi_term.js');
|
||||
const strUtil = require('./string_util.js');
|
||||
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
var _ = require('lodash');
|
||||
const util = require('util');
|
||||
const assert = require('assert');
|
||||
|
||||
exports.SpinnerMenuView = SpinnerMenuView;
|
||||
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var userDb = require('./database.js').dbs.user;
|
||||
|
||||
exports.getSystemLoginHistory = getSystemLoginHistory;
|
||||
|
||||
function getSystemLoginHistory(numRequested, cb) {
|
||||
|
||||
numRequested = Math.max(1, numRequested);
|
||||
|
||||
var loginHistory = [];
|
||||
|
||||
userDb.each(
|
||||
'SELECT user_id, user_name, timestamp ' +
|
||||
'FROM user_login_history ' +
|
||||
'ORDER BY timestamp DESC ' +
|
||||
'LIMIT ' + numRequested + ';',
|
||||
function historyRow(err, histEntry) {
|
||||
loginHistory.push( {
|
||||
userId : histEntry.user_id,
|
||||
userName : histEntry.user_name,
|
||||
timestamp : histEntry.timestamp,
|
||||
} );
|
||||
},
|
||||
function complete(err, recCount) {
|
||||
cb(err, loginHistory);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var View = require('./view.js').View;
|
||||
var TextView = require('./text_view.js').TextView;
|
||||
|
||||
var assert = require('assert');
|
||||
var _ = require('lodash');
|
||||
|
||||
function StatusBarView(options) {
|
||||
View.call(this, options);
|
||||
|
||||
var self = this;
|
||||
|
||||
|
||||
}
|
||||
|
||||
require('util').inherits(StatusBarView, View);
|
||||
|
||||
StatusBarView.prototype.redraw = function() {
|
||||
|
||||
StatusBarView.super_.prototype.redraw.call(this);
|
||||
|
||||
};
|
||||
|
||||
StatusBarView.prototype.setPanels = function(panels) {
|
||||
|
||||
/*
|
||||
"panels" : [
|
||||
{
|
||||
"text" : "things and stuff",
|
||||
"width" 20,
|
||||
...
|
||||
},
|
||||
{
|
||||
"width" : 40 // no text, etc... = spacer
|
||||
}
|
||||
]
|
||||
|
||||
|---------------------------------------------|
|
||||
| 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 } );
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
|
@ -293,7 +293,7 @@ function transformValue(transformerName, value) {
|
|||
}
|
||||
|
||||
// :TODO: Use explicit set of chars for paths & function/transforms such that } is allowed as fill/etc.
|
||||
const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]+))?}/g;
|
||||
const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:!([^:}]+))?(?::([^}]+))?}/g;
|
||||
|
||||
function getValue(obj, path) {
|
||||
const value = _.get(obj, path);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
// ENiGMA½
|
||||
const miscUtil = require('./misc_util.js');
|
||||
const ANSIEscapeParser = require('./ansi_escape_parser.js').ANSIEscapeParser;
|
||||
const ANSI = require('./ansi_term.js');
|
||||
|
||||
// deps
|
||||
|
@ -198,11 +197,6 @@ function isPrintable(s) {
|
|||
return !RE_NON_PRINTABLE.test(s);
|
||||
}
|
||||
|
||||
function stringLength(s) {
|
||||
// :TODO: See https://mathiasbynens.be/notes/javascript-unicode
|
||||
return s.length;
|
||||
}
|
||||
|
||||
function stripAllLineFeeds(s) {
|
||||
return s.replace(/\r?\n|[\r\u2028\u2029]/g, '');
|
||||
}
|
||||
|
@ -359,7 +353,7 @@ function formatCount(count, withAbbr = false, decimals = 2) {
|
|||
|
||||
// :TODO: See notes in word_wrap.js about need to consolidate the various ANSI related RegExp's
|
||||
//const REGEXP_ANSI_CONTROL_CODES = /(\x1b\x5b)([\?=;0-9]*?)([0-9A-ORZcf-npsu=><])/g;
|
||||
const REGEXP_ANSI_CONTROL_CODES = /(?:\x1b\x5b)([\?=;0-9]*?)([A-ORZcf-npsu=><])/g; // eslint-disable-line no-control-regex
|
||||
const REGEXP_ANSI_CONTROL_CODES = /(?:\x1b\x5b)([?=;0-9]*?)([A-ORZcf-npsu=><])/g; // eslint-disable-line no-control-regex
|
||||
const ANSI_OPCODES_ALLOWED_CLEAN = [
|
||||
//'A', 'B', // up, down
|
||||
//'C', 'D', // right, left
|
||||
|
@ -405,194 +399,6 @@ function cleanControlCodes(input, options) {
|
|||
return cleaned;
|
||||
}
|
||||
|
||||
function prepAnsi(input, options, cb) {
|
||||
if(!input) {
|
||||
return cb(null, '');
|
||||
}
|
||||
|
||||
options.termWidth = options.termWidth || 80;
|
||||
options.termHeight = options.termHeight || 25;
|
||||
options.cols = options.cols || options.termWidth || 80;
|
||||
options.rows = options.rows || options.termHeight || 'auto';
|
||||
options.startCol = options.startCol || 1;
|
||||
options.exportMode = options.exportMode || false;
|
||||
|
||||
const canvas = Array.from( { length : 'auto' === options.rows ? 25 : options.rows }, () => Array.from( { length : options.cols}, () => new Object() ) );
|
||||
const parser = new ANSIEscapeParser( { termHeight : options.termHeight, termWidth : options.termWidth } );
|
||||
|
||||
const state = {
|
||||
row : 0,
|
||||
col : 0,
|
||||
};
|
||||
|
||||
let lastRow = 0;
|
||||
|
||||
function ensureRow(row) {
|
||||
if(Array.isArray(canvas[row])) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas[row] = Array.from( { length : options.cols}, () => new Object() );
|
||||
}
|
||||
|
||||
parser.on('position update', (row, col) => {
|
||||
state.row = row - 1;
|
||||
state.col = col - 1;
|
||||
|
||||
lastRow = Math.max(state.row, lastRow);
|
||||
});
|
||||
|
||||
parser.on('literal', literal => {
|
||||
//
|
||||
// CR/LF are handled for 'position update'; we don't need the chars themselves
|
||||
//
|
||||
literal = literal.replace(/\r?\n|[\r\u2028\u2029]/g, '');
|
||||
|
||||
for(let c of literal) {
|
||||
if(state.col < options.cols && ('auto' === options.rows || state.row < options.rows)) {
|
||||
ensureRow(state.row);
|
||||
|
||||
canvas[state.row][state.col].char = c;
|
||||
|
||||
if(state.sgr) {
|
||||
canvas[state.row][state.col].sgr = state.sgr;
|
||||
state.sgr = null;
|
||||
}
|
||||
}
|
||||
|
||||
state.col += 1;
|
||||
}
|
||||
});
|
||||
|
||||
parser.on('control', (match, opCode) => {
|
||||
//
|
||||
// Movement is handled via 'position update', so we really only care about
|
||||
// display opCodes
|
||||
//
|
||||
switch(opCode) {
|
||||
case 'm' :
|
||||
state.sgr = (state.sgr || '') + match;
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
function getLastPopulatedColumn(row) {
|
||||
let col = row.length;
|
||||
while(--col > 0) {
|
||||
if(row[col].char || row[col].sgr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
parser.on('complete', () => {
|
||||
let output = '';
|
||||
let lastSgr = '';
|
||||
let line;
|
||||
|
||||
canvas.slice(0, lastRow + 1).forEach(row => {
|
||||
const lastCol = getLastPopulatedColumn(row) + 1;
|
||||
|
||||
let i;
|
||||
line = '';
|
||||
for(i = 0; i < lastCol; ++i) {
|
||||
const col = row[i];
|
||||
if(col.sgr) {
|
||||
lastSgr = col.sgr;
|
||||
}
|
||||
line += `${col.sgr || ''}${col.char || ' '}`;
|
||||
}
|
||||
|
||||
output += line;
|
||||
|
||||
if(i < row.length) {
|
||||
output += `${ANSI.blackBG()}${row.slice(i).map( () => ' ').join('')}${lastSgr}`;
|
||||
}
|
||||
|
||||
//if(options.startCol + options.cols < options.termWidth || options.forceLineTerm) {
|
||||
if(options.startCol + i < options.termWidth || options.forceLineTerm) {
|
||||
output += '\r\n';
|
||||
}
|
||||
});
|
||||
|
||||
if(options.exportMode) {
|
||||
//
|
||||
// If we're in export mode, we do some additional hackery:
|
||||
//
|
||||
// * Hard wrap ALL lines at <= 79 *characters* (not visible columns)
|
||||
// if a line must wrap early, we'll place a ESC[A ESC[<N>C where <N>
|
||||
// represents chars to get back to the position we were previously at
|
||||
//
|
||||
// * Replace contig spaces with ESC[<N>C as well to save... space.
|
||||
//
|
||||
// :TODO: this would be better to do as part of the processing above, but this will do for now
|
||||
const MAX_CHARS = 79 - 8; // 79 max, - 8 for max ESC seq's we may prefix a line with
|
||||
let exportOutput = '';
|
||||
|
||||
let m;
|
||||
let afterSeq;
|
||||
let wantMore;
|
||||
let renderStart;
|
||||
|
||||
splitTextAtTerms(output).forEach(fullLine => {
|
||||
renderStart = 0;
|
||||
|
||||
while(fullLine.length > 0) {
|
||||
let splitAt;
|
||||
const ANSI_REGEXP = ANSI.getFullMatchRegExp();
|
||||
wantMore = true;
|
||||
|
||||
while((m = ANSI_REGEXP.exec(fullLine))) {
|
||||
afterSeq = m.index + m[0].length;
|
||||
|
||||
if(afterSeq < MAX_CHARS) {
|
||||
// after current seq
|
||||
splitAt = afterSeq;
|
||||
} else {
|
||||
if(m.index < MAX_CHARS) {
|
||||
// before last found seq
|
||||
splitAt = m.index;
|
||||
wantMore = false; // can't eat up any more
|
||||
}
|
||||
|
||||
break; // seq's beyond this point are >= MAX_CHARS
|
||||
}
|
||||
}
|
||||
|
||||
if(splitAt) {
|
||||
if(wantMore) {
|
||||
splitAt = Math.min(fullLine.length, MAX_CHARS - 1);
|
||||
}
|
||||
} else {
|
||||
splitAt = Math.min(fullLine.length, MAX_CHARS - 1);
|
||||
}
|
||||
|
||||
const part = fullLine.slice(0, splitAt);
|
||||
fullLine = fullLine.slice(splitAt);
|
||||
renderStart += renderStringLength(part);
|
||||
exportOutput += `${part}\r\n`;
|
||||
|
||||
if(fullLine.length > 0) { // more to go for this line?
|
||||
exportOutput += `${ANSI.up()}${ANSI.right(renderStart)}`;
|
||||
} else {
|
||||
exportOutput += ANSI.up();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return cb(null, exportOutput);
|
||||
}
|
||||
|
||||
return cb(null, output);
|
||||
});
|
||||
|
||||
parser.parse(input);
|
||||
}
|
||||
|
||||
function isAnsiLine(line) {
|
||||
return isAnsi(line);// || renderStringLength(line) < line.length;
|
||||
}
|
||||
|
@ -622,6 +428,7 @@ function isFormattedLine(line) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// :TODO: rename to containsAnsi()
|
||||
function isAnsi(input) {
|
||||
if(!input || 0 === input.length) {
|
||||
return false;
|
||||
|
@ -647,7 +454,7 @@ function isAnsi(input) {
|
|||
*/
|
||||
|
||||
// :TODO: if a similar method is kept, use exec() until threshold
|
||||
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[\?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex
|
||||
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex
|
||||
const m = input.match(ANSI_DET_REGEXP) || [];
|
||||
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ function validateEmailAvail(data, cb) {
|
|||
//
|
||||
// See http://stackoverflow.com/questions/7786058/find-the-regex-used-by-html5-forms-for-validation
|
||||
//
|
||||
const emailRegExp = /[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
|
||||
const emailRegExp = /[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
|
||||
if(!emailRegExp.test(data)) {
|
||||
return cb(new Error('Invalid email address'));
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ function TextView(options) {
|
|||
this.textMaskChar = options.textMaskChar;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
this.drawText = function(s) {
|
||||
|
||||
//
|
||||
|
|
|
@ -115,13 +115,13 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
|
|||
assert(_.isObject(menuConfig));
|
||||
assert(_.isObject(theme));
|
||||
|
||||
// :TODO: merge in defaults (customization.defaults{} )
|
||||
// :TODO: apply generic stuff, e.g. "VM" (vs "VM1")
|
||||
// :TODO: merge in defaults (customization.defaults{} )
|
||||
// :TODO: apply generic stuff, e.g. "VM" (vs "VM1")
|
||||
|
||||
//
|
||||
// Create a *clone* of menuConfig (menu.hjson) then bring in
|
||||
// promptConfig (prompt.hjson)
|
||||
//
|
||||
//
|
||||
// Create a *clone* of menuConfig (menu.hjson) then bring in
|
||||
// promptConfig (prompt.hjson)
|
||||
//
|
||||
var mergedTheme = _.cloneDeep(menuConfig);
|
||||
|
||||
if(_.isObject(promptConfig.prompts)) {
|
||||
|
@ -163,28 +163,28 @@ function getMergedTheme(menuConfig, promptConfig, theme) {
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// menu.hjson can have a couple different structures:
|
||||
// 1) Explicit declaration of expected MCI code(s) under 'form:<id>' before a 'mci' block
|
||||
// (this allows multiple layout types defined by one menu for example)
|
||||
//
|
||||
// 2) Non-explicit declaration: 'mci' directly under 'form:<id>'
|
||||
//
|
||||
// theme.hjson has it's own mix:
|
||||
// 1) Explicit: Form ID before 'mci' (generally used where there are > 1 forms)
|
||||
//
|
||||
// 2) Non-explicit: 'mci' directly under an entry
|
||||
//
|
||||
// Additionally, #1 or #2 may be under an explicit key of MCI code(s) to match up
|
||||
// with menu.hjson in #1.
|
||||
//
|
||||
// * When theming an explicit menu.hjson entry (1), we will use a matching explicit
|
||||
// entry with a matching MCI code(s) key in theme.hjson (e.g. menu="ETVM"/theme="ETVM"
|
||||
// and fall back to generic if a match is not found.
|
||||
//
|
||||
// * If theme.hjson provides form ID's, use them. Otherwise, we'll apply directly assuming
|
||||
// there is a generic 'mci' block.
|
||||
//
|
||||
//
|
||||
// menu.hjson can have a couple different structures:
|
||||
// 1) Explicit declaration of expected MCI code(s) under 'form:<id>' before a 'mci' block
|
||||
// (this allows multiple layout types defined by one menu for example)
|
||||
//
|
||||
// 2) Non-explicit declaration: 'mci' directly under 'form:<id>'
|
||||
//
|
||||
// theme.hjson has it's own mix:
|
||||
// 1) Explicit: Form ID before 'mci' (generally used where there are > 1 forms)
|
||||
//
|
||||
// 2) Non-explicit: 'mci' directly under an entry
|
||||
//
|
||||
// Additionally, #1 or #2 may be under an explicit key of MCI code(s) to match up
|
||||
// with menu.hjson in #1.
|
||||
//
|
||||
// * When theming an explicit menu.hjson entry (1), we will use a matching explicit
|
||||
// entry with a matching MCI code(s) key in theme.hjson (e.g. menu="ETVM"/theme="ETVM"
|
||||
// and fall back to generic if a match is not found.
|
||||
//
|
||||
// * If theme.hjson provides form ID's, use them. Otherwise, we'll apply directly assuming
|
||||
// there is a generic 'mci' block.
|
||||
//
|
||||
function applyToForm(form, menuTheme, formKey) {
|
||||
if(_.isObject(form.mci)) {
|
||||
// non-explicit: no MCI code(s) key assumed since we found 'mci' directly under form ID
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var View = require('./view.js').View;
|
||||
var miscUtil = require('./misc_util.js');
|
||||
var strUtil = require('./string_util.js');
|
||||
var ansi = require('./ansi_term.js');
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
|
||||
exports.TickerTextView = TickerTextView;
|
||||
|
||||
function TickerTextView(options) {
|
||||
View.call(this, options);
|
||||
|
||||
var self = this;
|
||||
|
||||
this.text = options.text || '';
|
||||
this.tickerStyle = options.tickerStyle || 'rightToLeft';
|
||||
assert(this.tickerStyle in TickerTextView.TickerStyles);
|
||||
|
||||
// :TODO: Ticker |text| should have ANSI stripped before calculating any lengths/etc.
|
||||
// strUtil.ansiTextLength(s)
|
||||
// strUtil.pad(..., ignoreAnsi)
|
||||
// strUtil.stylizeString(..., ignoreAnsi)
|
||||
|
||||
this.tickerState = {};
|
||||
switch(this.tickerStyle) {
|
||||
case 'rightToLeft' :
|
||||
this.tickerState.pos = this.position.row + this.dimens.width;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
self.onTickerInterval = function() {
|
||||
switch(self.tickerStyle) {
|
||||
case 'rightToLeft' : self.updateRightToLeftTicker(); break;
|
||||
}
|
||||
};
|
||||
|
||||
self.updateRightToLeftTicker = function() {
|
||||
// if pos < start
|
||||
// drawRemain()
|
||||
// if pos + remain > end
|
||||
// drawRemain(0, spaceFor)
|
||||
// else
|
||||
// drawString() + remainPading
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
util.inherits(TickerTextView, View);
|
||||
|
||||
TickerTextView.TickerStyles = {
|
||||
leftToRight : 1,
|
||||
rightToLeft : 2,
|
||||
bounce : 3,
|
||||
slamLeft : 4,
|
||||
slamRight : 5,
|
||||
slamBounce : 6,
|
||||
decrypt : 7,
|
||||
typewriter : 8,
|
||||
};
|
||||
Object.freeze(TickerTextView.TickerStyles);
|
||||
|
||||
/*
|
||||
TickerTextView.TICKER_STYLES = [
|
||||
'leftToRight',
|
||||
'rightToLeft',
|
||||
'bounce',
|
||||
'slamLeft',
|
||||
'slamRight',
|
||||
'slamBounce',
|
||||
'decrypt',
|
||||
'typewriter',
|
||||
];
|
||||
*/
|
||||
|
||||
TickerTextView.prototype.controllerAttached = function() {
|
||||
// :TODO: call super
|
||||
};
|
||||
|
||||
TickerTextView.prototype.controllerDetached = function() {
|
||||
// :TODO: call super
|
||||
|
||||
};
|
||||
|
||||
TickerTextView.prototype.setText = function(text) {
|
||||
this.text = strUtil.stylizeString(text, this.textStyle);
|
||||
|
||||
if(!this.dimens || !this.dimens.width) {
|
||||
this.dimens.width = Math.ceil(this.text.length / 2);
|
||||
}
|
||||
};
|
|
@ -1,13 +1,11 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var MenuView = require('./menu_view.js').MenuView;
|
||||
var ansi = require('./ansi_term.js');
|
||||
var strUtil = require('./string_util.js');
|
||||
const MenuView = require('./menu_view.js').MenuView;
|
||||
const strUtil = require('./string_util.js');
|
||||
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
var _ = require('lodash');
|
||||
const util = require('util');
|
||||
const assert = require('assert');
|
||||
|
||||
exports.ToggleMenuView = ToggleMenuView;
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var userDb = require('./database.js').dbs.user;
|
||||
var Config = require('./config.js').config;
|
||||
const userDb = require('./database.js').dbs.user;
|
||||
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
|
||||
exports.getGroupsForUser = getGroupsForUser;
|
||||
exports.addUserToGroup = addUserToGroup;
|
||||
|
@ -13,23 +12,22 @@ exports.addUserToGroups = addUserToGroups;
|
|||
exports.removeUserFromGroup = removeUserFromGroup;
|
||||
|
||||
function getGroupsForUser(userId, cb) {
|
||||
var sql =
|
||||
'SELECT group_name ' +
|
||||
'FROM user_group_member ' +
|
||||
'WHERE user_id=?;';
|
||||
const sql =
|
||||
`SELECT group_name
|
||||
FROM user_group_member
|
||||
WHERE user_id=?;`;
|
||||
|
||||
var groups = [];
|
||||
const groups = [];
|
||||
|
||||
userDb.each(sql, [ userId ], function rowData(err, row) {
|
||||
userDb.each(sql, [ userId ], (err, row) => {
|
||||
if(err) {
|
||||
cb(err);
|
||||
return;
|
||||
} else {
|
||||
groups.push(row.group_name);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
groups.push(row.group_name);
|
||||
},
|
||||
function complete() {
|
||||
cb(null, groups);
|
||||
() => {
|
||||
return cb(null, groups);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -40,31 +38,31 @@ function addUserToGroup(userId, groupName, transOrDb, cb) {
|
|||
}
|
||||
|
||||
transOrDb.run(
|
||||
'REPLACE INTO user_group_member (group_name, user_id) ' +
|
||||
'VALUES(?, ?);',
|
||||
`REPLACE INTO user_group_member (group_name, user_id)
|
||||
VALUES(?, ?);`,
|
||||
[ groupName, userId ],
|
||||
function complete(err) {
|
||||
cb(err);
|
||||
err => {
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function addUserToGroups(userId, groups, transOrDb, cb) {
|
||||
|
||||
async.each(groups, function item(groupName, next) {
|
||||
addUserToGroup(userId, groupName, transOrDb, next);
|
||||
}, function complete(err) {
|
||||
cb(err);
|
||||
async.each(groups, (groupName, nextGroupName) => {
|
||||
return addUserToGroup(userId, groupName, transOrDb, nextGroupName);
|
||||
}, err => {
|
||||
return cb(err);
|
||||
});
|
||||
}
|
||||
|
||||
function removeUserFromGroup(userId, groupName, cb) {
|
||||
userDb.run(
|
||||
'DELETE FROM user_group_member ' +
|
||||
'WHERE group_name=? AND user_id=?;',
|
||||
`DELETE FROM user_group_member
|
||||
WHERE group_name=? AND user_id=?;`,
|
||||
[ groupName, userId ],
|
||||
function complete(err) {
|
||||
cb(err);
|
||||
err => {
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -166,20 +166,6 @@ function ViewController(options) {
|
|||
var propAsset;
|
||||
var propValue;
|
||||
|
||||
function callModuleMethod(path) {
|
||||
if('' === paths.extname(path)) {
|
||||
path += '.js';
|
||||
}
|
||||
|
||||
try {
|
||||
var methodMod = require(path);
|
||||
// :TODO: fix formData & extraArgs
|
||||
return methodMod[propAsset.asset](self.client.currentMenuModule, {}, {} );
|
||||
} catch(e) {
|
||||
self.client.log.error( { error : e.toString(), methodName : propAsset.asset }, 'Failed to execute asset method');
|
||||
}
|
||||
}
|
||||
|
||||
for(var propName in conf) {
|
||||
propAsset = asset.getViewPropertyAsset(conf[propName]);
|
||||
if(propAsset) {
|
||||
|
@ -211,7 +197,7 @@ function ViewController(options) {
|
|||
}
|
||||
} else {
|
||||
if(_.isString(propAsset.location)) {
|
||||
|
||||
// :TODO: clean this code up!
|
||||
} else {
|
||||
if('systemMethod' === propAsset.type) {
|
||||
// :TODO:
|
||||
|
@ -681,7 +667,7 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) {
|
|||
callback(err);
|
||||
});
|
||||
},
|
||||
/*
|
||||
/*
|
||||
function applyThemeCustomization(callback) {
|
||||
formConfig = formConfig || {};
|
||||
formConfig.mci = formConfig.mci || {};
|
||||
|
|
|
@ -13,7 +13,6 @@ const Log = require('./logger.js').log;
|
|||
|
||||
// deps
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('graceful-fs');
|
||||
const url = require('url');
|
||||
|
@ -111,7 +110,7 @@ class WebPasswordReset {
|
|||
.replace(/%USERNAME%/g, user.username)
|
||||
.replace(/%TOKEN%/g, user.properties.email_password_reset_token)
|
||||
.replace(/%RESET_URL%/g, resetUrl)
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
textTemplate = replaceTokens(textTemplate);
|
||||
|
@ -128,7 +127,11 @@ class WebPasswordReset {
|
|||
};
|
||||
|
||||
sendMail(message, (err, info) => {
|
||||
// :TODO: Log me!
|
||||
if(err) {
|
||||
Log.warn( { error : err.message }, 'Failed sending password reset email' );
|
||||
} else {
|
||||
Log.debug( { info : info }, 'Successfully sent password reset email');
|
||||
}
|
||||
|
||||
return callback(err);
|
||||
});
|
||||
|
@ -162,7 +165,7 @@ class WebPasswordReset {
|
|||
path : '^\\/reset_password\\?token\\=[a-f0-9]+$', // Config.contentServers.web.forgotPasswordPageTemplate
|
||||
handler : WebPasswordReset.routeResetPasswordGet,
|
||||
},
|
||||
// POST handler for performing the actual reset
|
||||
// POST handler for performing the actual reset
|
||||
{
|
||||
method : 'POST',
|
||||
path : '^\\/reset_password$',
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var _ = require('lodash');
|
||||
const renderStringLength = require('./string_util.js').renderStringLength;
|
||||
|
||||
exports.wordWrapText = wordWrapText2;
|
||||
// deps
|
||||
const assert = require('assert');
|
||||
const _ = require('lodash');
|
||||
|
||||
exports.wordWrapText = wordWrapText;
|
||||
|
||||
const SPACE_CHARS = [
|
||||
' ', '\f', '\n', '\r', '\v',
|
||||
|
@ -16,7 +18,7 @@ const SPACE_CHARS = [
|
|||
|
||||
const REGEXP_WORD_WRAP = new RegExp(`\t|[${SPACE_CHARS.join('')}]`, 'g');
|
||||
|
||||
function wordWrapText2(text, options) {
|
||||
function wordWrapText(text, options) {
|
||||
assert(_.isObject(options));
|
||||
assert(_.isNumber(options.width));
|
||||
|
||||
|
@ -99,119 +101,3 @@ function wordWrapText2(text, options) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
function wordWrapText(text, options) {
|
||||
//
|
||||
// options.*:
|
||||
// width : word wrap width
|
||||
// tabHandling : expand (default=expand)
|
||||
// tabWidth : tab width if tabHandling is 'expand' (default=4)
|
||||
// tabChar : character to use for tab expansion
|
||||
//
|
||||
assert(_.isObject(options), 'Missing options!');
|
||||
assert(_.isNumber(options.width), 'Missing options.width!');
|
||||
|
||||
options.tabHandling = options.tabHandling || 'expand';
|
||||
|
||||
if(!_.isNumber(options.tabWidth)) {
|
||||
options.tabWidth = 4;
|
||||
}
|
||||
|
||||
options.tabChar = options.tabChar || ' ';
|
||||
|
||||
//
|
||||
// Notes
|
||||
// * Sublime Text 3 for example considers spaces after a word
|
||||
// part of said word. For example, "word " would be wraped
|
||||
// in it's entirity.
|
||||
//
|
||||
// * Tabs in Sublime Text 3 are also treated as a word, so, e.g.
|
||||
// "\t" may resolve to " " and must fit within the space.
|
||||
//
|
||||
// * If a word is ultimately too long to fit, break it up until it does.
|
||||
//
|
||||
// RegExp below is JavaScript '\s' minus the '\t'
|
||||
//
|
||||
var re = new RegExp(
|
||||
'\t|[ \f\n\r\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006' +
|
||||
'\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]', 'g');
|
||||
var m;
|
||||
var wordStart = 0;
|
||||
var results = { wrapped : [ '' ] };
|
||||
var i = 0;
|
||||
var word;
|
||||
var wordLen;
|
||||
|
||||
function expandTab(col) {
|
||||
var remainWidth = options.tabWidth - (col % options.tabWidth);
|
||||
return new Array(remainWidth).join(options.tabChar);
|
||||
}
|
||||
|
||||
// :TODO: support wrapping pipe code text (e.g. ignore color codes, expand MCI codes)
|
||||
|
||||
function addWord() {
|
||||
word.match(new RegExp('.{0,' + options.width + '}', 'g')).forEach(function wrd(w) {
|
||||
//wordLen = self.getStringLength(w);
|
||||
|
||||
if(results.wrapped[i].length + w.length > options.width) {
|
||||
//if(results.wrapped[i].length + wordLen > width) {
|
||||
if(0 === i) {
|
||||
results.firstWrapRange = { start : wordStart, end : wordStart + w.length };
|
||||
//results.firstWrapRange = { start : wordStart, end : wordStart + wordLen };
|
||||
}
|
||||
// :TODO: Must handle len of |w| itself > options.width & split how ever many times required (e.g. handle paste)
|
||||
results.wrapped[++i] = w;
|
||||
} else {
|
||||
results.wrapped[i] += w;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
while((m = re.exec(text)) !== null) {
|
||||
word = text.substring(wordStart, re.lastIndex - 1);
|
||||
|
||||
switch(m[0].charAt(0)) {
|
||||
case ' ' :
|
||||
word += m[0];
|
||||
break;
|
||||
|
||||
case '\t' :
|
||||
//
|
||||
// Expand tab given position
|
||||
//
|
||||
// Nice info here: http://c-for-dummies.com/blog/?p=424
|
||||
//
|
||||
if('expand' === options.tabHandling) {
|
||||
word += expandTab(results.wrapped[i].length + word.length) + options.tabChar;
|
||||
} else {
|
||||
word += m[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
addWord();
|
||||
wordStart = re.lastIndex + m[0].length - 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Remainder
|
||||
//
|
||||
word = text.substring(wordStart);
|
||||
addWord();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
//const input = 'Hello, |04World! This |08i|02s a test it is \x1b[20Conly a test of the emergency broadcast system. What you see is not a joke!';
|
||||
//const input = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five enturies, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
|
||||
|
||||
/*
|
||||
const iconv = require('iconv-lite');
|
||||
const input = iconv.decode(require('graceful-fs').readFileSync('/home/nuskooler/Downloads/msg_out.txt'), 'cp437');
|
||||
|
||||
const opts = {
|
||||
width : 80,
|
||||
};
|
||||
|
||||
console.log(wordWrapText2(input, opts).wrapped, 'utf8')
|
||||
*/
|
Loading…
Reference in New Issue