diff --git a/art/themes/luciano_blocktronics/wfc.ans b/art/themes/luciano_blocktronics/wfc.ans index 79fe75b9..92a7f302 100644 Binary files a/art/themes/luciano_blocktronics/wfc.ans and b/art/themes/luciano_blocktronics/wfc.ans differ diff --git a/core/menu_module.js b/core/menu_module.js index f233b1f7..fd234934 100644 --- a/core/menu_module.js +++ b/core/menu_module.js @@ -575,8 +575,13 @@ exports.MenuModule = class MenuModule extends PluginModule { } } - //let artHeight; + const originalSubmitNotify = options.submitNotify; + options.submitNotify = () => { + if (_.isFunction(originalSubmitNotify)) { + originalSubmitNotify(); + } + if (prevVc) { prevVc.setFocus(true); } @@ -597,6 +602,9 @@ exports.MenuModule = class MenuModule extends PluginModule { options.viewController.setFocus(true); this.optionalMoveToPosition(position); + if (!options.position) { + options.position = position; + } theme.displayThemedPrompt(promptName, this.client, options, (err, artInfo) => { /* if(artInfo) { diff --git a/core/menu_view.js b/core/menu_view.js index 3b145bfa..ed2eb9fb 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -198,6 +198,10 @@ MenuView.prototype.getItems = function () { }; MenuView.prototype.getItem = function (index) { + if (index > this.items.length - 1) { + return null; + } + if (this.complexItems) { return this.items[index]; } diff --git a/core/theme.js b/core/theme.js index e97a11da..a08ccd39 100644 --- a/core/theme.js +++ b/core/theme.js @@ -651,6 +651,16 @@ function displayThemedPrompt(name, client, options, cb) { ? new ViewController({ client: client }) : options.viewController; + // adjust MCI positions relative to |position| + if (options.position) { + _.forEach(artInfo.mciMap, mci => { + if (mci.position) { + mci.position[0] = options.position.row; + mci.position[1] += options.position.col; + } + }); + } + const loadOpts = { promptName: name, mciMap: artInfo.mciMap, diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index 59455a91..2252ec6d 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -231,6 +231,9 @@ VerticalMenuView.prototype.onKeyPress = function (ch, key) { VerticalMenuView.prototype.getData = function () { const item = this.getItem(this.focusedItemIndex); + if (!item) { + return this.focusedItemIndex; + } return _.isString(item.data) ? item.data : this.focusedItemIndex; }; diff --git a/core/wfc.js b/core/wfc.js index b36070f8..a82e1b9f 100644 --- a/core/wfc.js +++ b/core/wfc.js @@ -2,12 +2,18 @@ const { MenuModule } = require('./menu_module'); const stringFormat = require('./string_format'); -const { getActiveConnectionList, AllConnections } = require('./client_connections'); +const { + getActiveConnectionList, + AllConnections, + getConnectionByNodeId, + removeClient, +} = require('./client_connections'); const StatLog = require('./stat_log'); const SysProps = require('./system_property'); const UserProps = require('./user_property'); const Log = require('./logger'); const Config = require('./config.js').get; +const { Errors } = require('./enig_error'); // deps const async = require('async'); @@ -25,13 +31,15 @@ const FormIds = { main: 0, help: 1, fullLog: 2, + confirmKickPrompt: 3, }; const MciViewIds = { main: { nodeStatus: 1, quickLogView: 2, - nodeStatusSelection: 3, + selectedNodeStatusInfo: 3, + confirmXy: 4, customRangeStart: 10, }, @@ -89,6 +97,17 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { } return cb(null); }, + kickSelectedNode: (formData, extraArgs, cb) => { + return this._confirmKickSelectedNode(cb); + }, + kickNodeYes: (formData, extraArgs, cb) => { + //this._startRefreshing(); + return this._kickSelectedNode(cb); + }, + kickNodeNo: (formData, extraArgs, cb) => { + //this._startRefreshing(); + return cb(null); + }, }; } @@ -151,7 +170,7 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { ); const nodeStatusSelectionView = this.getView( 'main', - MciViewIds.main.nodeStatusSelection + MciViewIds.main.selectedNodeStatusInfo ); const nodeStatusSelectionFormat = this.config.nodeStatusSelectionFormat || '{text}'; @@ -212,6 +231,79 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { super.leave(); } + _getSelectedNodeItem() { + const nodeStatusView = this.getView('main', MciViewIds.main.nodeStatus); + if (!nodeStatusView) { + return null; + } + + return nodeStatusView.getItem(nodeStatusView.getFocusItemIndex()); + } + + _confirmKickSelectedNode(cb) { + const nodeItem = this._getSelectedNodeItem(); + if (!nodeItem) { + return cb(null); + } + + const confirmView = this.getView('main', MciViewIds.main.confirmXy); + if (!confirmView) { + return cb( + Errors.MissingMci(`Missing prompt XY${MciViewIds.main.confirmXy} MCI`) + ); + } + + // disallow kicking self + if (this.client.node === parseInt(nodeItem.node)) { + return cb(null); + } + + const promptOptions = { + clearAtSubmit: true, + submitNotify: () => { + this._startRefreshing(); + }, + }; + + if (confirmView.dimens.width) { + promptOptions.clearWidth = confirmView.dimens.width; + } + + this._stopRefreshing(); + return this.promptForInput( + { + formName: 'confirmKickPrompt', + formId: FormIds.confirmKickPrompt, + promptName: this.config.confirmKickNodePrompt || 'confirmKickNodePrompt', + prevFormName: 'main', + position: confirmView.position, + }, + promptOptions, + err => { + return cb(err); + } + ); + } + + _kickSelectedNode(cb) { + const nodeItem = this._getSelectedNodeItem(); + if (!nodeItem) { + return cb(Errors.UnexpectedState('Expecting a selected node')); + } + + const client = getConnectionByNodeId(parseInt(nodeItem.node)); + if (!client) { + return cb( + Errors.UnexpectedState(`Expecting a client for node ID ${nodeItem.node}`) + ); + } + + // :TODO: optional kick art + + removeClient(client); + return cb(null); + } + _applyOpVisibility() { this.restoreUserIsVisible = this.client.user.isVisible();