Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0b8916194e
|
@ -11,6 +11,7 @@ const logger = require('./logger.js');
|
|||
const database = require('./database.js');
|
||||
const clientConns = require('./client_connections.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
const util = require('util');
|
||||
const _ = require('lodash');
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var logger = require('./logger.js');
|
||||
// ENiGMA½
|
||||
const logger = require('./logger.js');
|
||||
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
const moment = require('moment');
|
||||
|
||||
exports.getActiveConnections = getActiveConnections;
|
||||
exports.getActiveNodeList = getActiveNodeList;
|
||||
exports.addNewClient = addNewClient;
|
||||
exports.removeClient = removeClient;
|
||||
|
||||
var clientConnections = [];
|
||||
const clientConnections = [];
|
||||
exports.clientConnections = clientConnections;
|
||||
|
||||
function getActiveConnections() {
|
||||
return clientConnections;
|
||||
}
|
||||
function getActiveConnections() { return clientConnections; }
|
||||
|
||||
function getActiveNodeList(authUsersOnly) {
|
||||
|
||||
if(!_.isBoolean(authUsersOnly)) {
|
||||
authUsersOnly = true;
|
||||
}
|
||||
|
||||
function getActiveNodeList() {
|
||||
const now = moment();
|
||||
|
||||
return _.map(getActiveConnections(), ac => {
|
||||
let entry = {
|
||||
const activeConnections = getActiveConnections().filter(ac => {
|
||||
return ((authUsersOnly && ac.user.isAuthenticated()) || !authUsersOnly);
|
||||
});
|
||||
|
||||
return _.map(activeConnections, ac => {
|
||||
const entry = {
|
||||
node : ac.node,
|
||||
authenticated : ac.user.isAuthenticated(),
|
||||
userId : ac.user.userId,
|
||||
|
@ -46,13 +55,13 @@ function getActiveNodeList() {
|
|||
}
|
||||
|
||||
function addNewClient(client, clientSock) {
|
||||
var id = client.session.id = clientConnections.push(client) - 1;
|
||||
const id = client.session.id = clientConnections.push(client) - 1;
|
||||
|
||||
// Create a client specific logger
|
||||
// Note that this will be updated @ login with additional information
|
||||
client.log = logger.log.child( { clientId : id } );
|
||||
|
||||
var connInfo = {
|
||||
const connInfo = {
|
||||
ip : clientSock.remoteAddress,
|
||||
serverName : client.session.serverName,
|
||||
isSecure : client.session.isSecure,
|
||||
|
@ -71,7 +80,7 @@ function addNewClient(client, clientSock) {
|
|||
function removeClient(client) {
|
||||
client.end();
|
||||
|
||||
var i = clientConnections.indexOf(client);
|
||||
const i = clientConnections.indexOf(client);
|
||||
if(i > -1) {
|
||||
clientConnections.splice(i, 1);
|
||||
|
||||
|
@ -84,15 +93,3 @@ function removeClient(client) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* :TODO: make a public API elsewhere
|
||||
function getActiveClientInformation() {
|
||||
var info = {};
|
||||
|
||||
clientConnections.forEach(function connEntry(cc) {
|
||||
|
||||
});
|
||||
|
||||
return info;
|
||||
}
|
||||
*/
|
|
@ -122,10 +122,10 @@ function prepareTerminal(term) {
|
|||
function displayBanner(term) {
|
||||
// note: intentional formatting:
|
||||
term.pipeWrite(`
|
||||
|06Connected to |02EN|10i|02GMA|10½ |06BBS version |12|VN
|
||||
|06Copyright (c) 2014-2016 Bryan Ashby |14- |12http://l33t.codes/
|
||||
|06Updates & source |14- |12https://github.com/NuSkooler/enigma-bbs/
|
||||
|00`
|
||||
|06Connected to |02EN|10i|02GMA|10½ |06BBS version |12|VN
|
||||
|06Copyright (c) 2014-2016 Bryan Ashby |14- |12http://l33t.codes/
|
||||
|06Updates & source |14- |12https://github.com/NuSkooler/enigma-bbs/
|
||||
|00`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
class EnigError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
|
||||
if(typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
} else {
|
||||
this.stack = (new Error(message)).stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.EnigError = EnigError;
|
|
@ -0,0 +1,18 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
// ENiGMA½
|
||||
const Config = require('./config.js').config;
|
||||
const Log = require('./logger.js').log;
|
||||
|
||||
// deps
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = function(condition, message) {
|
||||
if(Config.debug.assertsEnabled) {
|
||||
assert.apply(this, arguments);
|
||||
} else if(!(condition)) {
|
||||
const stack = new Error().stack;
|
||||
Log.error( { condition : condition, stack : stack }, message || 'Assertion failed' );
|
||||
}
|
||||
};
|
|
@ -0,0 +1,327 @@
|
|||
/* 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;
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
|
||||
/*
|
||||
String formatting HEAVILY inspired by David Chambers string-format library
|
||||
and the mini-language branch specifically which was gratiously released
|
||||
under the DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE.
|
||||
|
||||
We need some extra functionality. Namely, support for RA style pipe codes
|
||||
and ANSI escape sequences.
|
||||
*/
|
||||
|
||||
class ValueError extends EnigError { }
|
||||
class KeyError extends EnigError { }
|
||||
|
||||
const SpecRegExp = {
|
||||
FillAlign : /^(.)?([<>=^])/,
|
||||
Sign : /^[ +-]/,
|
||||
Width : /^\d*/,
|
||||
Precision : /^\d+/,
|
||||
};
|
||||
|
||||
function tokenizeFormatSpec(spec) {
|
||||
const tokens = {
|
||||
fill : '',
|
||||
align : '',
|
||||
sign : '',
|
||||
'#' : false,
|
||||
'0' : false,
|
||||
width : '',
|
||||
',' : false,
|
||||
precision : '',
|
||||
type : '',
|
||||
};
|
||||
|
||||
let index = 0;
|
||||
let match;
|
||||
|
||||
function incIndexByMatch() {
|
||||
index += match[0].length;
|
||||
}
|
||||
|
||||
match = SpecRegExp.FillAlign.exec(spec);
|
||||
if(match) {
|
||||
if(match[1]) {
|
||||
tokens.fill = match[1];
|
||||
}
|
||||
tokens.align = match[2];
|
||||
incIndexByMatch();
|
||||
}
|
||||
|
||||
match = SpecRegExp.Sign.exec(spec.slice(index));
|
||||
if(match) {
|
||||
tokens.sign = match[0];
|
||||
incIndexByMatch();
|
||||
}
|
||||
|
||||
if('#' === spec.charAt(index)) {
|
||||
tokens['#'] = true;
|
||||
++index;
|
||||
}
|
||||
|
||||
if('0' === spec.charAt(index)) {
|
||||
tokens['0'] = true;
|
||||
++index;
|
||||
}
|
||||
|
||||
match = SpecRegExp.Width.exec(spec.slice(index));
|
||||
tokens.width = match[0];
|
||||
incIndexByMatch();
|
||||
|
||||
if(',' === spec.charAt(index)) {
|
||||
tokens[','] = true;
|
||||
++index;
|
||||
}
|
||||
|
||||
if('.' === spec.charAt(index)) {
|
||||
++index;
|
||||
|
||||
match = SpecRegExp.Precision.exec(spec.slice(index));
|
||||
if(!match) {
|
||||
throw new ValueError('Format specifier missing precision');
|
||||
}
|
||||
|
||||
tokens.precision = match[0];
|
||||
incIndexByMatch();
|
||||
}
|
||||
|
||||
if(index < spec.length) {
|
||||
tokens.type = spec.charAt(index);
|
||||
++index;
|
||||
}
|
||||
|
||||
if(index < spec.length) {
|
||||
throw new ValueError('Invalid conversion specification');
|
||||
}
|
||||
|
||||
if(tokens[','] && 's' === tokens.type) {
|
||||
throw new ValueError(`Cannot specify ',' with 's'`); // eslint-disable-line quotes
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function quote(s) {
|
||||
return `"${s.replace(/"/g, '\\"')}"`;
|
||||
}
|
||||
|
||||
function getPadAlign(align) {
|
||||
return {
|
||||
'<' : 'right',
|
||||
'>' : 'left',
|
||||
'^' : 'center',
|
||||
}[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
|
||||
|
||||
if('' !== tokens.type && 's' !== tokens.type) {
|
||||
throw new ValueError(`Unknown format code "${tokens.type}" for String object`);
|
||||
}
|
||||
|
||||
if(tokens[',']) {
|
||||
throw new ValueError(`Cannot specify ',' with 's'`); // eslint-disable-line quotes
|
||||
}
|
||||
|
||||
if(tokens.sign) {
|
||||
throw new ValueError('Sign not allowed in string format specifier');
|
||||
}
|
||||
|
||||
if(tokens['#']) {
|
||||
throw new ValueError('Alternate form (#) not allowed in string format specifier');
|
||||
}
|
||||
|
||||
if('=' === align) {
|
||||
throw new ValueError('"=" alignment not allowed in string format specifier');
|
||||
}
|
||||
|
||||
return pad(value.slice(0, precision), parseInt(tokens.width), fill, getPadAlign(align));
|
||||
}
|
||||
|
||||
const FormatNumRegExp = {
|
||||
UpperType : /[A-Z]/,
|
||||
ExponentRep : /e[+-](?=\d$)/,
|
||||
};
|
||||
|
||||
function formatNumberHelper(n, precision, type) {
|
||||
if(FormatNumRegExp.UpperType.test(type)) {
|
||||
return formatNumberHelper(n, precision, type.toLowerCase()).toUpperCase();
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case 'c' : return String.fromCharCode(n);
|
||||
case 'd' : return n.toString(10);
|
||||
case 'b' : return n.toString(2);
|
||||
case 'o' : return n.toString(8);
|
||||
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 '%' : return formatNumberHelper(n * 100, precision, 'f') + '%';
|
||||
case '' : return formatNumberHelper(n, precision, 'd');
|
||||
|
||||
default :
|
||||
throw new ValueError(`Unknown format code "${type}" for object of type 'float'`);
|
||||
}
|
||||
}
|
||||
|
||||
function formatNumber(value, tokens) {
|
||||
const fill = tokens.fill || (tokens['0'] ? '0' : ' ');
|
||||
const align = tokens.align || (tokens['0'] ? '=' : '>');
|
||||
const width = Number(tokens.width);
|
||||
const type = tokens.type || (tokens.precision ? 'g' : '');
|
||||
|
||||
if( [ 'c', 'd', 'b', 'o', 'x', 'X' ].indexOf(type) > -1) {
|
||||
if(0 !== value % 1) {
|
||||
throw new ValueError(`Cannot format non-integer with format specifier "${type}"`);
|
||||
}
|
||||
|
||||
if('' !== tokens.sign && 'c' !== type) {
|
||||
throw new ValueError(`Sign not allowed with integer format specifier 'c'`); // eslint-disable-line quotes
|
||||
}
|
||||
|
||||
if(tokens[','] && 'd' !== type) {
|
||||
throw new ValueError(`Cannot specify ',' with '${type}'`);
|
||||
}
|
||||
|
||||
if('' !== tokens.precision) {
|
||||
throw new ValueError('Precision not allowed in integer format specifier');
|
||||
}
|
||||
} else if( [ 'e', 'E', 'f', 'F', 'g', 'G', '%' ].indexOf(type) > - 1) {
|
||||
if(tokens['#']) {
|
||||
throw new ValueError('Alternate form (#) not allowed in float format specifier');
|
||||
}
|
||||
}
|
||||
|
||||
const s = formatNumberHelper(Math.abs(value), Number(tokens.precision || 6), type);
|
||||
const sign = value < 0 || 1 / value < 0 ?
|
||||
'-' :
|
||||
'-' === tokens.sign ? '' : tokens.sign;
|
||||
|
||||
const prefix = tokens['#'] && ( [ 'b', 'o', 'x', 'X' ].indexOf(type) > -1 ) ? '0' + type : '';
|
||||
|
||||
if(tokens[',']) {
|
||||
const match = /^(\d*)(.*)$/.exec(s);
|
||||
const separated = match[1].replace(/.(?=(...)+$)/g, '$&,') + match[2];
|
||||
|
||||
if('=' !== align) {
|
||||
return pad(sign + separated, width, fill, getPadAlign(align));
|
||||
}
|
||||
|
||||
if('0' === fill) {
|
||||
const shortfall = Math.max(0, width - sign.length - separated.length);
|
||||
const digits = /^\d*/.exec(separated)[0].length;
|
||||
let padding = '';
|
||||
// :TODO: do this differntly...
|
||||
for(let n = 0; n < shortfall; n++) {
|
||||
padding = ((digits + n) % 4 === 3 ? ',' : '0') + padding;
|
||||
}
|
||||
|
||||
return sign + (/^,/.test(padding) ? '0' : '') + padding + separated;
|
||||
}
|
||||
|
||||
return sign + pad(separated, width - sign.length, fill, getPadAlign('>'));
|
||||
}
|
||||
|
||||
if(0 === width) {
|
||||
return sign + prefix + s;
|
||||
}
|
||||
|
||||
if('=' === align) {
|
||||
return sign + prefix + pad(s, width - sign.length - prefix.length, fill, getPadAlign('>'));
|
||||
}
|
||||
|
||||
return pad(sign + prefix + s, width, fill, getPadAlign(align));
|
||||
}
|
||||
|
||||
const transformers = {
|
||||
// String standard
|
||||
toUpperCase : String.prototype.toUpperCase,
|
||||
toLowerCase : String.prototype.toLowerCase,
|
||||
|
||||
// some super l33b BBS styles!!
|
||||
styleUpper : (s) => stylizeString(s, 'upper'),
|
||||
styleLower : (s) => stylizeString(s, 'lower'),
|
||||
styleTitle : (s) => stylizeString(s, 'title'),
|
||||
styleFirstLower : (s) => stylizeString(s, 'first lower'),
|
||||
styleSmallVowels : (s) => stylizeString(s, 'small vowels'),
|
||||
styleBigVowels : (s) => stylizeString(s, 'big vowels'),
|
||||
styleSmallI : (s) => stylizeString(s, 'small i'),
|
||||
styleMixed : (s) => stylizeString(s, 'mixed'),
|
||||
styleL33t : (s) => stylizeString(s, 'l33t'),
|
||||
};
|
||||
|
||||
function transformValue(transformerName, value) {
|
||||
if(transformerName in transformers) {
|
||||
const transformer = transformers[transformerName];
|
||||
value = transformer.apply(value, [ value ] );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// :TODO: Use explicit set of chars for paths & function/transforms such that } is allowed as fill/etc.
|
||||
const REGEXP_BASIC_FORMAT = /{([^.!:}]+(?:\.[^.!:}]+)*)(?:\!([^:}]+))?(?:\:([^}]+))?}/g;
|
||||
|
||||
function getValue(obj, path) {
|
||||
const value = _.get(obj, path);
|
||||
if(value) {
|
||||
return _.isFunction(value) ? value() : value;
|
||||
}
|
||||
|
||||
throw new KeyError(quote(path));
|
||||
}
|
||||
|
||||
module.exports = function format(fmt, obj) {
|
||||
|
||||
const re = REGEXP_BASIC_FORMAT;
|
||||
let match;
|
||||
let pos;
|
||||
let out = '';
|
||||
do {
|
||||
pos = re.lastIndex;
|
||||
match = re.exec(fmt);
|
||||
|
||||
if(match) {
|
||||
if(match.index > pos) {
|
||||
out += fmt.slice(pos, match.index);
|
||||
}
|
||||
|
||||
const objPath = match[1];
|
||||
const transformer = match[2];
|
||||
const formatSpec = match[3];
|
||||
|
||||
let value = getValue(obj, objPath);
|
||||
if(transformer) {
|
||||
value = transformValue(transformer, value);
|
||||
}
|
||||
|
||||
const tokens = tokenizeFormatSpec(formatSpec || '');
|
||||
|
||||
if(!isNaN(parseInt(value))) {
|
||||
out += formatNumber(value, tokens);
|
||||
} else {
|
||||
out += formatString(value, tokens);
|
||||
}
|
||||
}
|
||||
|
||||
} while(0 !== re.lastIndex);
|
||||
|
||||
// remainder
|
||||
if(pos < fmt.length) {
|
||||
out += fmt.slice(pos);
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
54
core/view.js
54
core/view.js
|
@ -1,18 +1,19 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var events = require('events');
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
var ansi = require('./ansi_term.js');
|
||||
var colorCodes = require('./color_codes.js');
|
||||
// ENiGMA½
|
||||
const events = require('events');
|
||||
const util = require('util');
|
||||
const ansi = require('./ansi_term.js');
|
||||
const colorCodes = require('./color_codes.js');
|
||||
const enigAssert = require('./enigma_assert.js');
|
||||
|
||||
var _ = require('lodash');
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
|
||||
exports.View = View;
|
||||
exports.VIEW_SPECIAL_KEY_MAP_DEFAULT = VIEW_SPECIAL_KEY_MAP_DEFAULT;
|
||||
|
||||
var VIEW_SPECIAL_KEY_MAP_DEFAULT = {
|
||||
const VIEW_SPECIAL_KEY_MAP_DEFAULT = {
|
||||
accept : [ 'return' ],
|
||||
exit : [ 'esc' ],
|
||||
backspace : [ 'backspace', 'del' ],
|
||||
|
@ -27,11 +28,13 @@ var VIEW_SPECIAL_KEY_MAP_DEFAULT = {
|
|||
clearLine : [ 'ctrl + y' ],
|
||||
};
|
||||
|
||||
exports.VIEW_SPECIAL_KEY_MAP_DEFAULT = VIEW_SPECIAL_KEY_MAP_DEFAULT;
|
||||
|
||||
function View(options) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
assert(_.isObject(options));
|
||||
assert(_.isObject(options.client));
|
||||
enigAssert(_.isObject(options));
|
||||
enigAssert(_.isObject(options.client));
|
||||
|
||||
var self = this;
|
||||
|
||||
|
@ -131,7 +134,7 @@ View.prototype.setPosition = function(pos) {
|
|||
this.position.col = parseInt(arguments[1], 10);
|
||||
}
|
||||
|
||||
// santaize
|
||||
// sanatize
|
||||
this.position.row = Math.max(this.position.row, 1);
|
||||
this.position.col = Math.max(this.position.col, 1);
|
||||
this.position.row = Math.min(this.position.row, this.client.term.termHeight);
|
||||
|
@ -139,25 +142,23 @@ View.prototype.setPosition = function(pos) {
|
|||
};
|
||||
|
||||
View.prototype.setDimension = function(dimens) {
|
||||
assert(_.isObject(dimens) && _.isNumber(dimens.height) && _.isNumber(dimens.width));
|
||||
enigAssert(_.isObject(dimens) && _.isNumber(dimens.height) && _.isNumber(dimens.width));
|
||||
|
||||
this.dimens = dimens;
|
||||
this.autoScale = { height : false, width : false };
|
||||
};
|
||||
|
||||
View.prototype.setHeight = function(height) {
|
||||
height = parseInt(height, 10);
|
||||
assert(_.isNumber(height));
|
||||
// :TODO: assert height is within this.client.term.termHeight
|
||||
height = parseInt(height) || 1;
|
||||
height = Math.min(height, this.client.term.termHeight);
|
||||
|
||||
this.dimens.height = height;
|
||||
this.autoScale.height = false;
|
||||
};
|
||||
|
||||
View.prototype.setWidth = function(width) {
|
||||
width = parseInt(width);
|
||||
assert(_.isNumber(width));
|
||||
// :TODO: assert width is appropriate for this.client.term.termWidth
|
||||
width = parseInt(width) || 1;
|
||||
width = Math.min(width, this.client.term.termWidth);
|
||||
|
||||
this.dimens.width = width;
|
||||
this.autoScale.width = false;
|
||||
|
@ -168,7 +169,7 @@ View.prototype.getSGR = function() {
|
|||
};
|
||||
|
||||
View.prototype.getStyleSGR = function(n) {
|
||||
assert(_.isNumber(n));
|
||||
n = parseInt(n) || 0;
|
||||
return this['styleSGR' + n];
|
||||
};
|
||||
|
||||
|
@ -241,21 +242,22 @@ View.prototype.redraw = function() {
|
|||
};
|
||||
|
||||
View.prototype.setFocus = function(focused) {
|
||||
assert(this.acceptsFocus, 'View does not accept focus');
|
||||
enigAssert(this.acceptsFocus, 'View does not accept focus');
|
||||
|
||||
this.hasFocus = focused;
|
||||
this.restoreCursor();
|
||||
};
|
||||
|
||||
View.prototype.onKeyPress = function(ch, key) {
|
||||
if(false === this.hasFocus) {
|
||||
console.log('doh!'); // :TODO: fix me -- assert here?
|
||||
enigAssert(this.hasFocus, 'View does not have focus');
|
||||
enigAssert(this.acceptsInput, 'View does not accept input');
|
||||
|
||||
if(!this.hasFocus || !this.acceptsInput) {
|
||||
return;
|
||||
}
|
||||
assert(this.hasFocus, 'View does not have focus');
|
||||
assert(this.acceptsInput, 'View does not accept input');
|
||||
|
||||
if(key) {
|
||||
assert(this.specialKeyMap, 'No special key map defined');
|
||||
enigAssert(this.specialKeyMap, 'No special key map defined');
|
||||
|
||||
if(this.isKeyMapped('accept', key.name)) {
|
||||
this.emit('action', 'accept', key);
|
||||
|
@ -265,7 +267,7 @@ View.prototype.onKeyPress = function(ch, key) {
|
|||
}
|
||||
|
||||
if(ch) {
|
||||
assert(1 === ch.length);
|
||||
enigAssert(1 === ch.length);
|
||||
}
|
||||
|
||||
this.emit('key press', ch, key);
|
||||
|
|
|
@ -745,6 +745,10 @@
|
|||
value: { command: "O" }
|
||||
action: @menu:mainMenuOnelinerz
|
||||
}
|
||||
{
|
||||
value: { command: "R" }
|
||||
action: @menu:mainMenuRumorz
|
||||
}
|
||||
{
|
||||
value: { command: "CHAT"}
|
||||
action: @menu:ercClient
|
||||
|
@ -1108,6 +1112,92 @@
|
|||
}
|
||||
}
|
||||
|
||||
mainMenuRumorz: {
|
||||
desc: Rumorz
|
||||
module: rumorz
|
||||
options: {
|
||||
cls: true
|
||||
}
|
||||
config: {
|
||||
art: {
|
||||
entries: RUMORS
|
||||
add: RUMORADD
|
||||
}
|
||||
}
|
||||
form: {
|
||||
0: {
|
||||
mci: {
|
||||
VM1: {
|
||||
focus: false
|
||||
height: 10
|
||||
}
|
||||
TM2: {
|
||||
argName: addOrExit
|
||||
items: [ "yeah!", "nah" ]
|
||||
"hotKeys" : { "Y" : 0, "N" : 1, "Q" : 1 }
|
||||
submit: true
|
||||
focus: true
|
||||
}
|
||||
}
|
||||
submit: {
|
||||
*: [
|
||||
{
|
||||
value: { addOrExit: 0 }
|
||||
action: @method:viewAddScreen
|
||||
}
|
||||
{
|
||||
value: { addOrExit: null }
|
||||
action: @systemMethod:nextMenu
|
||||
}
|
||||
]
|
||||
}
|
||||
actionKeys: [
|
||||
{
|
||||
keys: [ "escape" ]
|
||||
action: @systemMethod:nextMenu
|
||||
}
|
||||
]
|
||||
},
|
||||
1: {
|
||||
mci: {
|
||||
ET1: {
|
||||
focus: true
|
||||
maxLength: 70
|
||||
argName: rumor
|
||||
}
|
||||
TL2: {
|
||||
width: 60
|
||||
}
|
||||
TM3: {
|
||||
argName: addOrCancel
|
||||
items: [ "add", "cancel" ]
|
||||
"hotKeys" : { "A" : 0, "C" : 1, "Q" : 1 }
|
||||
submit: true
|
||||
}
|
||||
}
|
||||
|
||||
submit: {
|
||||
*: [
|
||||
{
|
||||
value: { addOrCancel: 0 }
|
||||
action: @method:addEntry
|
||||
}
|
||||
{
|
||||
value: { addOrCancel: 1 }
|
||||
action: @method:cancelAdd
|
||||
}
|
||||
]
|
||||
}
|
||||
actionKeys: [
|
||||
{
|
||||
keys: [ "escape" ]
|
||||
action: @method:cancelAdd
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ercClient: {
|
||||
art: erc
|
||||
module: erc_client
|
||||
|
|
|
@ -7,6 +7,7 @@ const getModDatabasePath = require('../core/database.js').getModDatabasePath;
|
|||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const theme = require('../core/theme.js');
|
||||
const ansi = require('../core/ansi_term.js');
|
||||
const stringFormat = require('../core/string_format.js');
|
||||
|
||||
// deps
|
||||
const sqlite3 = require('sqlite3');
|
||||
|
@ -145,7 +146,7 @@ function OnelinerzModule(options) {
|
|||
const tsFormat = config.timestampFormat || 'ddd h:mma';
|
||||
|
||||
entriesView.setItems(entries.map( e => {
|
||||
return listFormat.format( {
|
||||
return stringFormat(listFormat, {
|
||||
userId : e.user_id,
|
||||
username : e.user_name,
|
||||
oneliner : e.oneliner,
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -271,6 +271,31 @@
|
|||
}
|
||||
}
|
||||
|
||||
mainMenuRumorz: {
|
||||
config: {
|
||||
listFormat: "|00|11 {rumor}"
|
||||
focusListFormat: "|00|15> |14{rumor}"
|
||||
}
|
||||
0: {
|
||||
mci: {
|
||||
VM1: { height: 14 }
|
||||
TM2: {
|
||||
focusTextStyle: upper
|
||||
items: [ "yes", "no" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
1: {
|
||||
mci: {
|
||||
ET1: { width: 60 }
|
||||
TL2: { width: 60 }
|
||||
TM3: {
|
||||
focusTextStyle: upper
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bbsList: {
|
||||
0: {
|
||||
mci: {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
var ViewController = require('../core/view_controller.js').ViewController;
|
||||
var getActiveNodeList = require('../core/client_connections.js').getActiveNodeList;
|
||||
// ENiGMA½
|
||||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||
const ViewController = require('../core/view_controller.js').ViewController;
|
||||
const getActiveNodeList = require('../core/client_connections.js').getActiveNodeList;
|
||||
|
||||
var moment = require('moment');
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var _ = require('lodash');
|
||||
// deps
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
|
||||
exports.moduleInfo = {
|
||||
name : 'Who\'s Online',
|
||||
|
@ -17,26 +17,9 @@ exports.moduleInfo = {
|
|||
packageName : 'codes.l33t.enigma.whosonline'
|
||||
};
|
||||
|
||||
/*
|
||||
node
|
||||
userName
|
||||
userId
|
||||
action
|
||||
note
|
||||
affils
|
||||
timeOnSec
|
||||
location
|
||||
realName
|
||||
serverName (Telnet, SSH, ...)
|
||||
|
||||
default
|
||||
{node} - {username} - {action} - {timeOnSec}
|
||||
|
||||
*/
|
||||
|
||||
exports.getModule = WhosOnlineModule;
|
||||
|
||||
var MciCodeIds = {
|
||||
const MciCodeIds = {
|
||||
OnlineList : 1,
|
||||
};
|
||||
|
||||
|
@ -47,30 +30,29 @@ function WhosOnlineModule(options) {
|
|||
require('util').inherits(WhosOnlineModule, MenuModule);
|
||||
|
||||
WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
|
||||
var self = this;
|
||||
var vc = self.viewControllers.allViews = new ViewController( { client : self.client } );
|
||||
const self = this;
|
||||
const vc = self.viewControllers.allViews = new ViewController( { client : self.client } );
|
||||
|
||||
async.series(
|
||||
[
|
||||
function callParentMciReady(callback) {
|
||||
WhosOnlineModule.super_.prototype.mciReady.call(self, mciData, callback);
|
||||
return WhosOnlineModule.super_.prototype.mciReady.call(self, mciData, callback);
|
||||
},
|
||||
function loadFromConfig(callback) {
|
||||
var loadOpts = {
|
||||
const loadOpts = {
|
||||
callingMenu : self,
|
||||
mciMap : mciData.menu,
|
||||
noInput : true,
|
||||
};
|
||||
|
||||
vc.loadFromMenuConfig(loadOpts, callback);
|
||||
return vc.loadFromMenuConfig(loadOpts, callback);
|
||||
},
|
||||
function populateList(callback) {
|
||||
var onlineListView = vc.getView(MciCodeIds.OnlineList);
|
||||
|
||||
const listFormat = self.menuConfig.config.listFormat || '{node} - {userName} - {action} - {timeOn}';
|
||||
const nonAuthUser = self.menuConfig.config.nonAuthUser || 'Logging In';
|
||||
const otherUnknown = self.menuConfig.config.otherUnknown || 'N/A';
|
||||
const onlineList = getActiveNodeList().slice(0, onlineListView.height);
|
||||
const onlineListView = vc.getView(MciCodeIds.OnlineList);
|
||||
const listFormat = self.menuConfig.config.listFormat || '{node} - {userName} - {action} - {timeOn}';
|
||||
const nonAuthUser = self.menuConfig.config.nonAuthUser || 'Logging In';
|
||||
const otherUnknown = self.menuConfig.config.otherUnknown || 'N/A';
|
||||
const onlineList = getActiveNodeList(self.menuConfig.config.authUsersOnly).slice(0, onlineListView.height);
|
||||
|
||||
onlineListView.setItems(_.map(onlineList, oe => {
|
||||
if(oe.authenticated) {
|
||||
|
@ -85,16 +67,16 @@ WhosOnlineModule.prototype.mciReady = function(mciData, cb) {
|
|||
}));
|
||||
|
||||
onlineListView.focusItems = onlineListView.items;
|
||||
|
||||
onlineListView.redraw();
|
||||
callback(null);
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
],
|
||||
function complete(err) {
|
||||
if(err) {
|
||||
self.client.log.error( { error : err.toString() }, 'Error loading who\'s online');
|
||||
self.client.log.error( { error : err.message }, 'Error loading who\'s online');
|
||||
}
|
||||
cb(err);
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,6 @@ const resolvePath = require('./core/misc_util.js').resolvePath;
|
|||
// deps
|
||||
const _ = require('lodash');
|
||||
const async = require('async');
|
||||
const assert = require('assert');
|
||||
const inq = require('inquirer');
|
||||
const mkdirsSync = require('fs-extra').mkdirsSync;
|
||||
const fs = require('fs');
|
||||
|
|
Loading…
Reference in New Issue