diff --git a/core/ansi_escape_parser.js b/core/ansi_escape_parser.js index f551cd5b..fb7ea732 100644 --- a/core/ansi_escape_parser.js +++ b/core/ansi_escape_parser.js @@ -226,7 +226,7 @@ function ANSIEscapeParser(options) { self.lastMciCode = fullMciCode; - self.graphicRenditionForErase = _.clone(self.graphicRendition, true); + self.graphicRenditionForErase = _.clone(self.graphicRendition); } diff --git a/core/config.js b/core/config.js index 98d0f9dd..ff614dfc 100644 --- a/core/config.js +++ b/core/config.js @@ -1,17 +1,19 @@ /* jslint node: true */ 'use strict'; -var miscUtil = require('./misc_util.js'); +// ENiGMA½ +const miscUtil = require('./misc_util.js'); -var fs = require('fs'); -var paths = require('path'); -var async = require('async'); -var _ = require('lodash'); -var hjson = require('hjson'); -var assert = require('assert'); +// deps +const fs = require('fs'); +const paths = require('path'); +const async = require('async'); +const _ = require('lodash'); +const hjson = require('hjson'); +const assert = require('assert'); -exports.init = init; -exports.getDefaultPath = getDefaultPath; +exports.init = init; +exports.getDefaultPath = getDefaultPath; function hasMessageConferenceAndArea(config) { assert(_.isObject(config.messageConferences)); // we create one ourself! @@ -43,38 +45,45 @@ function init(configPath, cb) { async.waterfall( [ function loadUserConfig(callback) { - if(_.isString(configPath)) { - fs.readFile(configPath, { encoding : 'utf8' }, function configData(err, data) { - if(err) { - callback(err); - } else { - try { - var configJson = hjson.parse(data); - callback(null, configJson); - } catch(e) { - callback(e); - } - } - }); - } else { - callback(null, { } ); + if(!_.isString(configPath)) { + return callback(null, { } ); } + + fs.readFile(configPath, { encoding : 'utf8' }, (err, configData) => { + if(err) { + return callback(err); + } + + let configJson; + try { + configJson = hjson.parse(configData); + } catch(e) { + return callback(e); + } + + return callback(null, configJson); + }); }, function mergeWithDefaultConfig(configJson, callback) { - var mergedConfig = _.merge(getDefaultConfig(), configJson, function mergeCustomizer(conf1, conf2) { - // Arrays should always concat - if(_.isArray(conf1)) { - // :TODO: look for collisions & override dupes - return conf1.concat(conf2); + + const mergedConfig = _.mergeWith( + getDefaultConfig(), + configJson, (conf1, conf2) => { + // Arrays should always concat + if(_.isArray(conf1)) { + // :TODO: look for collisions & override dupes + return conf1.concat(conf2); + } } - }); + ); - callback(null, mergedConfig); + return callback(null, mergedConfig); }, function validate(mergedConfig, callback) { // // Various sections must now exist in config // + // :TODO: Logic is broken here: if(hasMessageConferenceAndArea(mergedConfig)) { var msgAreasErr = new Error('Please create at least one message conference and area!'); msgAreasErr.code = 'EBADCONFIG'; @@ -92,7 +101,7 @@ function init(configPath, cb) { } function getDefaultPath() { - var base = miscUtil.resolvePath('~/'); + const base = miscUtil.resolvePath('~/'); if(base) { // e.g. /home/users/joeuser/.config/enigma-bbs/config.hjson return paths.join(base, '.config', 'enigma-bbs', 'config.hjson'); diff --git a/core/download_queue.js b/core/download_queue.js index 7254b9c8..6bfbd47f 100644 --- a/core/download_queue.js +++ b/core/download_queue.js @@ -8,7 +8,11 @@ module.exports = class DownloadQueue { this.client = client; if(!Array.isArray(this.client.user.downloadQueue)) { - this.loadFromProperty(client); + if(this.client.user.properties.dl_queue) { + this.loadFromProperty(this.client.user.properties.dl_queue); + } else { + this.client.user.downloadQueue = []; + } } } diff --git a/core/enig_error.js b/core/enig_error.js index 0378ee00..103a98b2 100644 --- a/core/enig_error.js +++ b/core/enig_error.js @@ -30,3 +30,10 @@ exports.Errors = { ExternalProcess : (reason, reasonCode) => new EnigError('External process error', -32005, reason, reasonCode), MissingConfig : (reason, reasonCode) => new EnigError('Missing configuration', -32006, reason, reasonCode), }; + +exports.ErrorReasons = { + AlreadyThere : 'ALREADYTHERE', + InvalidNextMenu : 'BADNEXT', + NoPreviousMenu : 'NOPREV', + NoConditionMatch : 'NOCONDMATCH', +}; \ No newline at end of file diff --git a/core/file_area.js b/core/file_area.js index 99e4a80f..ab847b05 100644 --- a/core/file_area.js +++ b/core/file_area.js @@ -45,7 +45,7 @@ function getAvailableFileAreas(client, options) { // perform ACS check per conf & omit internal if desired const allAreas = _.map(Config.fileBase.areas, (areaInfo, areaTag) => Object.assign(areaInfo, { areaTag : areaTag } )); - return _.omit(allAreas, areaInfo => { + return _.omitBy(allAreas, areaInfo => { if(!options.includeSystemInternal && isInternalArea(areaInfo.areaTag)) { return true; } diff --git a/core/fse.js b/core/fse.js index d7da12ed..aae8f713 100644 --- a/core/fse.js +++ b/core/fse.js @@ -274,7 +274,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul } getFooterName() { - return 'footer' + _.capitalize(this.footerMode); // e.g. 'footerEditor', 'footerEditorMenu', ... + return 'footer' + _.upperFirst(this.footerMode); // e.g. 'footerEditor', 'footerEditorMenu', ... } getFormId(name) { @@ -431,9 +431,9 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul callback(null); }, function displayFooterArt(callback) { - var footerArt = self.menuConfig.config.art[options.footerName]; + const footerArt = self.menuConfig.config.art[options.footerName]; - theme.displayThemedAsset( +or theme.displayThemedAsset( footerArt, self.client, { font : self.menuConfig.font }, @@ -723,7 +723,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul if(posView) { this.client.term.rawWrite(ansi.savePos()); // :TODO: Use new formatting techniques here, e.g. state.cursorPositionRow, cursorPositionCol and cursorPositionFormat - posView.setText(_.padLeft(String(pos.row + 1), 2, '0') + ',' + _.padLeft(String(pos.col + 1), 2, '0')); + posView.setText(_.padStart(String(pos.row + 1), 2, '0') + ',' + _.padEnd(String(pos.col + 1), 2, '0')); this.client.term.rawWrite(ansi.restorePos()); } } diff --git a/core/menu_module.js b/core/menu_module.js index 95356f90..2553335b 100644 --- a/core/menu_module.js +++ b/core/menu_module.js @@ -104,7 +104,7 @@ exports.MenuModule = class MenuModule extends PluginModule { self.client.once('cursor position report', pos => { pausePosition = { row : pos[0], col : 1 }; - self.client.log.trace('After art position recorded', { position : pausePosition } ); + self.client.log.trace('After art position recorded', pausePosition ); return callback(null); }); diff --git a/core/menu_stack.js b/core/menu_stack.js index d1fc15bb..f524ce75 100644 --- a/core/menu_stack.js +++ b/core/menu_stack.js @@ -133,37 +133,34 @@ module.exports = class MenuStack { currentModuleInfo.savedState = currentModuleInfo.instance.getSaveState(); currentModuleInfo.instance.leave(); + + if(modInst.menuConfig.options.menuFlags.includes('noHistory')) { + this.pop().instance.leave(); // leave & remove current + } } - const noHistory = modInst.menuConfig.options.menuFlags.indexOf('noHistory') > -1; - - const stackToLog = _.map(self.stack, stackEntry => stackEntry.name); - - if(!noHistory) { - self.push({ - name : name, - instance : modInst, - extraArgs : loadOpts.extraArgs, - }); - - stackToLog.push(name); - } else { - stackToLog.push(`${name} (noHistory)`); - } + self.push({ + name : name, + instance : modInst, + extraArgs : loadOpts.extraArgs, + }); // restore previous state if requested if(options && options.savedState) { modInst.restoreSavedState(options.savedState); } - modInst.enter(); + const stackEntries = self.stack.map(stackEntry => { + let name = stackEntry.name; + if(stackEntry.instance.menuConfig.options.menuFlags.length > 0) { + name += ` (${stackEntry.instance.menuConfig.options.menuFlags.join(', ')})`; + } + return name; + }); - self.client.log.trace( - { - stack : stackToLog - }, - 'Updated menu stack' - ); + self.client.log.trace( { stack : stackEntries }, 'Updated menu stack' ); + + modInst.enter(); if(cb) { cb(null); diff --git a/core/menu_util.js b/core/menu_util.js index 68751f33..7e15d6da 100644 --- a/core/menu_util.js +++ b/core/menu_util.js @@ -94,18 +94,20 @@ function loadMenu(options, cb) { { moduleName : modData.name, extraArgs : options.extraArgs, config : modData.config, info : modData.mod.modInfo }, 'Creating menu module instance'); + let moduleInstance; try { - const moduleInstance = new modData.mod.getModule({ + moduleInstance = new modData.mod.getModule({ menuName : options.name, menuConfig : modData.config, extraArgs : options.extraArgs, client : options.client, lastMenuResult : options.lastMenuResult, - }); - return callback(null, moduleInstance); + }); } catch(e) { return callback(e); } + + return callback(null, moduleInstance); } ], (err, modInst) => { @@ -127,8 +129,8 @@ function getFormConfigByIDAndMap(menuConfig, formId, mciMap, cb) { return; } - var formForId = menuConfig.form[formId]; - var mciReqKey = _.filter(_.pluck(_.sortBy(mciMap, 'code'), 'code'), function(mci) { + const formForId = menuConfig.form[formId]; + const mciReqKey = _.filter(_.map(_.sortBy(mciMap, 'code'), 'code'), (mci) => { return MCIViewFactory.UserViewCodes.indexOf(mci) > -1; }).join(''); diff --git a/core/message_area.js b/core/message_area.js index 95cadf1c..8fe250a1 100644 --- a/core/message_area.js +++ b/core/message_area.js @@ -37,7 +37,7 @@ function getAvailableMessageConferences(client, options) { options = options || { includeSystemInternal : false }; // perform ACS check per conf & omit system_internal if desired - return _.omit(Config.messageConferences, (conf, confTag) => { + return _.omitBy(Config.messageConferences, (conf, confTag) => { if(!options.includeSystemInternal && 'system_internal' === confTag) { return true; } @@ -73,7 +73,7 @@ function getAvailableMessageAreasByConfTag(confTag, options) { return areas; } else { // perform ACS check per area - return _.omit(areas, area => { + return _.omitBy(areas, area => { return !options.client.acs.hasMessageAreaRead(area); }); } diff --git a/core/module_util.js b/core/module_util.js index 9834fe5a..3e51207c 100644 --- a/core/module_util.js +++ b/core/module_util.js @@ -86,7 +86,7 @@ function loadModulesForCategory(category, iterator, complete) { }); async.each(jsModules, (file, next) => { -+ loadModule(paths.basename(file, '.js'), category, (err, mod) => { + loadModule(paths.basename(file, '.js'), category, (err, mod) => { iterator(err, mod); return next(); }); diff --git a/core/theme.js b/core/theme.js index 90ff0cd4..ee67b14e 100644 --- a/core/theme.js +++ b/core/theme.js @@ -1,21 +1,20 @@ /* jslint node: true */ 'use strict'; -var Config = require('./config.js').config; -var art = require('./art.js'); -var ansi = require('./ansi_term.js'); -var miscUtil = require('./misc_util.js'); -var Log = require('./logger.js').log; -var configCache = require('./config_cache.js'); -var getFullConfig = require('./config_util.js').getFullConfig; -var asset = require('./asset.js'); -var ViewController = require('./view_controller.js').ViewController; +const Config = require('./config.js').config; +const art = require('./art.js'); +const ansi = require('./ansi_term.js'); +const Log = require('./logger.js').log; +const configCache = require('./config_cache.js'); +const getFullConfig = require('./config_util.js').getFullConfig; +const asset = require('./asset.js'); +const ViewController = require('./view_controller.js').ViewController; -var fs = require('fs'); -var paths = require('path'); -var async = require('async'); -var _ = require('lodash'); -var assert = require('assert'); +const fs = require('fs'); +const paths = require('path'); +const async = require('async'); +const _ = require('lodash'); +const assert = require('assert'); exports.getThemeArt = getThemeArt; exports.getAvailableThemes = getAvailableThemes; @@ -100,10 +99,10 @@ function loadTheme(themeID, cb) { }); } -var availableThemes = {}; +const availableThemes = {}; -var IMMUTABLE_MCI_PROPERTIES = [ - 'maxLength', 'argName', 'submit', 'validate' +const IMMUTABLE_MCI_PROPERTIES = [ + 'maxLength', 'argName', 'submit', 'validate' ]; function getMergedTheme(menuConfig, promptConfig, theme) { @@ -119,44 +118,44 @@ function getMergedTheme(menuConfig, promptConfig, theme) { // var mergedTheme = _.cloneDeep(menuConfig); - if(_.isObject(promptConfig.prompts)) { - mergedTheme.prompts = _.cloneDeep(promptConfig.prompts); - } - - // - // Add in data we won't be altering directly from the theme - // - mergedTheme.info = theme.info; - mergedTheme.helpers = theme.helpers; - - // - // merge customizer to disallow immutable MCI properties - // - var mciCustomizer = function(objVal, srcVal, key) { + if(_.isObject(promptConfig.prompts)) { + mergedTheme.prompts = _.cloneDeep(promptConfig.prompts); + } + + // + // Add in data we won't be altering directly from the theme + // + mergedTheme.info = theme.info; + mergedTheme.helpers = theme.helpers; + + // + // merge customizer to disallow immutable MCI properties + // + var mciCustomizer = function(objVal, srcVal, key) { return IMMUTABLE_MCI_PROPERTIES.indexOf(key) > -1 ? objVal : srcVal; }; - - function getFormKeys(fromObj) { - return _.remove(_.keys(fromObj), function pred(k) { - return !isNaN(k); // remove all non-numbers - }); - } - - function mergeMciProperties(dest, src) { - Object.keys(src).forEach(function mciEntry(mci) { - _.merge(dest[mci], src[mci], mciCustomizer); - }); - } - - function applyThemeMciBlock(dest, src, formKey) { - if(_.isObject(src.mci)) { - mergeMciProperties(dest, src.mci); - } else { - if(_.has(src, [ formKey, 'mci' ])) { - mergeMciProperties(dest, src[formKey].mci); - } - } - } + + function getFormKeys(fromObj) { + return _.remove(_.keys(fromObj), function pred(k) { + return !isNaN(k); // remove all non-numbers + }); + } + + function mergeMciProperties(dest, src) { + Object.keys(src).forEach(function mciEntry(mci) { + _.mergeWith(dest[mci], src[mci], mciCustomizer); + }); + } + + function applyThemeMciBlock(dest, src, formKey) { + if(_.isObject(src.mci)) { + mergeMciProperties(dest, src.mci); + } else { + if(_.has(src, [ formKey, 'mci' ])) { + mergeMciProperties(dest, src[formKey].mci); + } + } + } // // menu.hjson can have a couple different structures: @@ -180,103 +179,103 @@ function getMergedTheme(menuConfig, promptConfig, theme) { // * 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 - applyThemeMciBlock(form.mci, menuTheme, formKey); - - } else { - var menuMciCodeKeys = _.remove(_.keys(form), function pred(k) { - return k === k.toUpperCase(); // remove anything not uppercase - }); - - menuMciCodeKeys.forEach(function mciKeyEntry(mciKey) { - var applyFrom; - if(_.has(menuTheme, [ mciKey, 'mci' ])) { - applyFrom = menuTheme[mciKey]; - } else { - applyFrom = menuTheme; - } - - applyThemeMciBlock(form[mciKey].mci, applyFrom); - }); - } - } + 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 + applyThemeMciBlock(form.mci, menuTheme, formKey); + + } else { + var menuMciCodeKeys = _.remove(_.keys(form), function pred(k) { + return k === k.toUpperCase(); // remove anything not uppercase + }); + + menuMciCodeKeys.forEach(function mciKeyEntry(mciKey) { + var applyFrom; + if(_.has(menuTheme, [ mciKey, 'mci' ])) { + applyFrom = menuTheme[mciKey]; + } else { + applyFrom = menuTheme; + } + + applyThemeMciBlock(form[mciKey].mci, applyFrom); + }); + } + } - [ 'menus', 'prompts' ].forEach(function areaEntry(sectionName) { - _.keys(mergedTheme[sectionName]).forEach(function menuEntry(menuName) { - var createdFormSection = false; - var mergedThemeMenu = mergedTheme[sectionName][menuName]; - - if(_.has(theme, [ 'customization', sectionName, menuName ])) { - var menuTheme = theme.customization[sectionName][menuName]; - - // config block is direct assign/overwrite - // :TODO: should probably be _.merge() - if(menuTheme.config) { - mergedThemeMenu.config = _.assign(mergedThemeMenu.config || {}, menuTheme.config); - } - - if('menus' === sectionName) { - if(_.isObject(mergedThemeMenu.form)) { - getFormKeys(mergedThemeMenu.form).forEach(function formKeyEntry(formKey) { - applyToForm(mergedThemeMenu.form[formKey], menuTheme, formKey); - }); - } else { - if(_.isObject(menuTheme.mci)) { - // - // Not specified at menu level means we apply anything from the - // theme to form.0.mci{} - // - mergedThemeMenu.form = { 0 : { mci : { } } }; - mergeMciProperties(mergedThemeMenu.form[0], menuTheme); - createdFormSection = true; - } - } - } else if('prompts' === sectionName) { - // no 'form' or form keys for prompts -- direct to mci - applyToForm(mergedThemeMenu, menuTheme); - } - } - - // - // Finished merging for this menu/prompt - // - // If the following conditions are true, set runtime.autoNext to true: - // * This is a menu - // * There is/was no explicit 'form' section - // * There is no 'prompt' specified - // - if('menus' === sectionName && !_.isString(mergedThemeMenu.prompt) && - (createdFormSection || !_.isObject(mergedThemeMenu.form))) - { - mergedThemeMenu.runtime = _.merge(mergedThemeMenu.runtime || {}, { autoNext : true } ); - } - }); - }); + [ 'menus', 'prompts' ].forEach(function areaEntry(sectionName) { + _.keys(mergedTheme[sectionName]).forEach(function menuEntry(menuName) { + var createdFormSection = false; + var mergedThemeMenu = mergedTheme[sectionName][menuName]; + + if(_.has(theme, [ 'customization', sectionName, menuName ])) { + var menuTheme = theme.customization[sectionName][menuName]; + + // config block is direct assign/overwrite + // :TODO: should probably be _.merge() + if(menuTheme.config) { + mergedThemeMenu.config = _.assign(mergedThemeMenu.config || {}, menuTheme.config); + } + + if('menus' === sectionName) { + if(_.isObject(mergedThemeMenu.form)) { + getFormKeys(mergedThemeMenu.form).forEach(function formKeyEntry(formKey) { + applyToForm(mergedThemeMenu.form[formKey], menuTheme, formKey); + }); + } else { + if(_.isObject(menuTheme.mci)) { + // + // Not specified at menu level means we apply anything from the + // theme to form.0.mci{} + // + mergedThemeMenu.form = { 0 : { mci : { } } }; + mergeMciProperties(mergedThemeMenu.form[0], menuTheme); + createdFormSection = true; + } + } + } else if('prompts' === sectionName) { + // no 'form' or form keys for prompts -- direct to mci + applyToForm(mergedThemeMenu, menuTheme); + } + } + + // + // Finished merging for this menu/prompt + // + // If the following conditions are true, set runtime.autoNext to true: + // * This is a menu + // * There is/was no explicit 'form' section + // * There is no 'prompt' specified + // + if('menus' === sectionName && !_.isString(mergedThemeMenu.prompt) && + (createdFormSection || !_.isObject(mergedThemeMenu.form))) + { + mergedThemeMenu.runtime = _.merge(mergedThemeMenu.runtime || {}, { autoNext : true } ); + } + }); + }); return mergedTheme; } function initAvailableThemes(cb) { - var menuConfig; - var promptConfig; + var menuConfig; + var promptConfig; async.waterfall( [ - function loadMenuConfig(callback) { - getFullConfig(Config.general.menuFile, function gotConfig(err, mc) { - menuConfig = mc; - callback(err); - }); - }, - function loadPromptConfig(callback) { - getFullConfig(Config.general.promptFile, function gotConfig(err, pc) { - promptConfig = pc; - callback(err); - }); - }, + function loadMenuConfig(callback) { + getFullConfig(Config.general.menuFile, function gotConfig(err, mc) { + menuConfig = mc; + callback(err); + }); + }, + function loadPromptConfig(callback) { + getFullConfig(Config.general.promptFile, function gotConfig(err, pc) { + promptConfig = pc; + callback(err); + }); + }, function getDir(callback) { fs.readdir(Config.paths.themes, function dirRead(err, files) { callback(err, files); @@ -294,7 +293,7 @@ function initAvailableThemes(cb) { filtered.forEach(function themeEntry(themeId) { loadTheme(themeId, function themeLoaded(err, theme, themePath) { if(!err) { - availableThemes[themeId] = getMergedTheme(menuConfig, promptConfig, theme); + availableThemes[themeId] = getMergedTheme(menuConfig, promptConfig, theme); configCache.on('recached', function recached(path) { if(themePath === path) { @@ -339,17 +338,17 @@ function getRandomTheme() { } function setClientTheme(client, themeId) { - var desc; - - try { - client.currentTheme = getAvailableThemes()[themeId]; - desc = 'Set client theme'; - } catch(e) { - client.currentTheme = getAvailableThemes()[Config.defaults.theme]; - desc = 'Failed setting theme by supplied ID; Using default'; - } - - client.log.debug( { themeId : themeId, info : client.currentTheme.info }, desc); + var desc; + + try { + client.currentTheme = getAvailableThemes()[themeId]; + desc = 'Set client theme'; + } catch(e) { + client.currentTheme = getAvailableThemes()[Config.defaults.theme]; + desc = 'Failed setting theme by supplied ID; Using default'; + } + + client.log.debug( { themeId : themeId, info : client.currentTheme.info }, desc); } function getThemeArt(options, cb) { diff --git a/core/user.js b/core/user.js index e7b14740..53272fff 100644 --- a/core/user.js +++ b/core/user.js @@ -338,7 +338,7 @@ User.prototype.removeProperty = function(propName, cb) { return cb(err); } } - ) + ); }; User.prototype.persistProperties = function(properties, cb) { @@ -474,7 +474,7 @@ function generatePasswordDerivedKeySalt(cb) { function generatePasswordDerivedKey(password, salt, cb) { password = new Buffer(password).toString('hex'); - crypto.pbkdf2(password, salt, User.PBKDF2.iterations, User.PBKDF2.keyLen, function onDerivedKey(err, dk) { + crypto.pbkdf2(password, salt, User.PBKDF2.iterations, User.PBKDF2.keyLen, 'sha1', function onDerivedKey(err, dk) { if(err) { cb(err); } else { diff --git a/core/view_controller.js b/core/view_controller.js index 37f41fad..392471cc 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -73,8 +73,9 @@ function ViewController(options) { self.switchFocus(actionForKey.viewId); self.submitForm(key); } else if(_.isString(actionForKey.action)) { + const formData = self.getFocusedView() ? self.getFormData() : { }; self.handleActionWrapper( - { ch : ch, key : key }, // formData + Object.assign( { ch : ch, key : key }, formData ), // formData + key info actionForKey); // actionBlock } } else { @@ -115,6 +116,7 @@ function ViewController(options) { self.emit('submit', this.getFormData(key)); }; + // :TODO: replace this in favor of overriding toJSON() for various things such that logging will *never* output them this.getLogFriendlyFormData = function(formData) { // :TODO: these fields should be part of menu.json sensitiveMembers[] var safeFormData = _.cloneDeep(formData); @@ -585,7 +587,7 @@ ViewController.prototype.loadFromPromptConfig = function(options, cb) { for(var c = 0; c < menuSubmit.length; ++c) { var actionBlock = menuSubmit[c]; - if(_.isEqual(formData.value, actionBlock.value, self.actionBlockValueComparator)) { + if(_.isEqualWith(formData.value, actionBlock.value, self.actionBlockValueComparator)) { self.handleActionWrapper(formData, actionBlock); break; // there an only be one... } @@ -713,7 +715,7 @@ ViewController.prototype.loadFromMenuConfig = function(options, cb) { for(var c = 0; c < confForFormId.length; ++c) { var actionBlock = confForFormId[c]; - if(_.isEqual(formData.value, actionBlock.value, self.actionBlockValueComparator)) { + if(_.isEqualWith(formData.value, actionBlock.value, self.actionBlockValueComparator)) { self.handleActionWrapper(formData, actionBlock); break; // there an only be one... } @@ -827,38 +829,6 @@ ViewController.prototype.getFormData = function(key) { this.client.log.error( { error : e.message }, 'Exception caught gathering form data' ); } }); - /* - - var viewData; - var view; - for(var id in this.views) { - try { - view = this.views[id]; - viewData = view.getData(); - if(!_.isUndefined(viewData)) { - if(_.isString(view.submitArgName)) { - formData.value[view.submitArgName] = viewData; - } else { - formData.value[id] = viewData; - } - } - } catch(e) { - this.client.log.error(e); // :TODO: Log better ;) - } - }*/ return formData; }; - -/* -ViewController.prototype.formatMenuArgs = function(args) { - var self = this; - - return _.mapValues(args, function val(value) { - if('string' === typeof value) { - return self.formatMCIString(value); - } - return value; - }); -}; -*/ \ No newline at end of file diff --git a/mods/file_area_list.js b/mods/file_area_list.js index edcd9edb..f973a70e 100644 --- a/mods/file_area_list.js +++ b/mods/file_area_list.js @@ -509,7 +509,7 @@ exports.getModule = class FileAreaList extends MenuModule { displayDetailsSection(sectionName, clearArea, cb) { const self = this; - const name = `details${_.capitalize(sectionName)}`; + const name = `details${_.upperFirst(sectionName)}`; async.series( [ diff --git a/mods/file_base_download_manager.js b/mods/file_base_download_manager.js index 2bd166bf..f6b0c1b0 100644 --- a/mods/file_base_download_manager.js +++ b/mods/file_base_download_manager.js @@ -61,12 +61,20 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule { viewItemInfo : (formData, extraArgs, cb) => { }, removeItem : (formData, extraArgs, cb) => { - const selectedItem = formData.value.queueItem; - this.dlQueue.removeItems(selectedItem); + const selectedItem = this.dlQueue.items[formData.value.queueItem]; + if(!selectedItem) { + return cb(null); + } + + this.dlQueue.removeItems(selectedItem.fileId); + + // :TODO: broken: does not redraw menu properly - needs fixed! return this.updateDownloadQueueView(cb); }, clearQueue : (formData, extraArgs, cb) => { this.dlQueue.clear(); + + // :TODO: broken: does not redraw menu properly - needs fixed! return this.updateDownloadQueueView(cb); } }; diff --git a/mods/msg_area_view_fse.js b/mods/msg_area_view_fse.js index 51794399..129476ae 100644 --- a/mods/msg_area_view_fse.js +++ b/mods/msg_area_view_fse.js @@ -32,7 +32,8 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule { const self = this; - this.menuMethods = { + // assign *additional* menuMethods + Object.assign(this.menuMethods, { nextMessage : (formData, extraArgs, cb) => { if(self.messageIndex + 1 < self.messageList.length) { self.messageIndex++; @@ -85,7 +86,7 @@ exports.getModule = class AreaViewFSEModule extends FullScreenEditorModule { self.client.log(extraArgs, 'Missing extraArgs.menu'); return cb(null); } - }; + }); } diff --git a/mods/whos_online.js b/mods/whos_online.js index 8d38646d..a0a87829 100644 --- a/mods/whos_online.js +++ b/mods/whos_online.js @@ -56,7 +56,7 @@ exports.getModule = class WhosOnlineModule extends MenuModule { onlineListView.setItems(_.map(onlineList, oe => { if(oe.authenticated) { - oe.timeOn = _.capitalize(oe.timeOn.humanize()); + oe.timeOn = _.upperFirst(oe.timeOn.humanize()); } else { [ 'realName', 'location', 'affils', 'timeOn' ].forEach(m => { oe[m] = otherUnknown; diff --git a/package.json b/package.json index 902c34e5..2a07b7d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "enigma-bbs", - "version": "0.0.3-alpha", + "version": "0.0.4-alpha", "description": "ENiGMA½ Bulletin Board System", "author": "Bryan Ashby ", "license": "BSD-2-Clause", @@ -18,29 +18,32 @@ "retro" ], "dependencies": { - "async": "^1.5.1", + "async": "^2.1.4", "binary": "0.3.x", - "buffers": "0.1.x", + "buffers": "NuSkooler/node-buffers", "bunyan": "^1.7.1", "farmhash": "^1.2.1", - "fs-extra": "0.26.x", - "gaze": "^0.5.2", - "hjson": "1.7.x", + "fs-extra": "^2.0.0", + "gaze": "^1.1.2", + "hashids": "^1.1.1", + "hjson": "^2.4.1", "iconv-lite": "^0.4.13", - "inquirer": "^1.1.0", + "inquirer": "^3.0.1", "later": "1.2.0", - "lodash": "^3.10.1", + "lodash": "^4.17.4", + "mime-types": "^2.1.12", "minimist": "1.2.x", "moment": "^2.11.0", "node-uuid": "^1.4.7", "ptyw.js": "NuSkooler/ptyw.js", "sqlite3": "^3.1.1", "ssh2": "^0.5.1", - "temp": "^0.8.3", - "hashids" : "^1.1.1", - "mime-types" : "^2.1.12" + "temp": "^0.8.3" + }, + "devDependencies": { + "lodash-migrate": "^0.3.16" }, "engines": { - "node": ">=4.2.0" + "node": ">=6.9.2" } }