Files
neorelay/files/glowing-bear/command-menu.js.inc
NIA Sanitized Release Publisher 7141326ea0 Sanitized public release v1.0.3
Source-Tag: v1.0.3
Manifest-SHA256: b7b09bf48f9e092ed8ad82f99c0319d6c3837d0a1549bd0cc4a374276c0f3896
2026-07-20 22:35:36 +00:00

147 lines
7.2 KiB
PHP

var commandHooks = null;
var commandHooksRequest = null;
var commandMenuGeneration = 0;
var suppressCommandMenuKeypress = false;
var serverCommandFallbacks = [
{command:'defcon',args:'[<level>]',description:'Set or show Ergo emergency restrictions',insertion:'/quote DEFCON',serverCommand:true},
{command:'deoper',args:'',description:'Remove IRC operator privileges',insertion:'/quote DEOPER',serverCommand:true},
{command:'dline',args:'[<duration>] <ip>/<net> [<reason>] || LIST',description:'Add or list IP/network bans',insertion:'/quote DLINE',serverCommand:true},
{command:'kline',args:'[<duration>] <mask> [<reason>] || LIST',description:'Add or list client-mask bans',insertion:'/quote KLINE',serverCommand:true},
{command:'uban',args:'ADD|DEL|LIST|INFO <target>',description:'Manage unified bans',insertion:'/quote UBAN',serverCommand:true},
{command:'undline',args:'<ip>/<net>',description:'Remove an IP/network ban',insertion:'/quote UNDLINE',serverCommand:true},
{command:'unkline',args:'<mask>',description:'Remove a client-mask ban',insertion:'/quote UNKLINE',serverCommand:true}
];
var mergeCommandHooks = function(hooks) {
var unique = Object.create(null);
var hasOwn = Object.prototype.hasOwnProperty;
hooks.forEach(function(hook) {
var key = String(hook.command || '').toLowerCase();
if (key && (!hasOwn.call(unique, key) || hook.priority > unique[key].priority)) {
unique[key] = Object.assign({}, hook, {command:key});
}
});
serverCommandFallbacks.forEach(function(hook) {
if (!hasOwn.call(unique, hook.command)) unique[hook.command] = hook;
});
return Object.keys(unique).map(function(key){return unique[key];}).sort(function(left,right){return left.command.localeCompare(right.command);});
};
$scope.commandMenuOpen = false;
$scope.commandMenuLoading = false;
$scope.commandMenuMatches = [];
$scope.commandMenuIndex = 0;
var closeCommandMenu = function() {
$scope.commandMenuOpen = false;
$scope.commandMenuLoading = false;
$scope.commandMenuMatches = [];
$scope.commandMenuIndex = 0;
};
var updateCommandMenu = function() {
var match = /^\/([^\s]*)$/.exec($scope.command || '');
if (!match) {
closeCommandMenu();
return;
}
$scope.commandMenuOpen = true;
$scope.commandMenuIndex = 0;
if (commandHooks === null) {
$scope.commandMenuLoading = true;
if (commandHooksRequest === null) {
var requestGeneration = commandMenuGeneration;
commandHooksRequest = connection.requestCommandHooks().then(function(hooks) {
if (requestGeneration !== commandMenuGeneration) {
return;
}
commandHooks = mergeCommandHooks(hooks);
commandHooksRequest = null;
updateCommandMenu();
}, function() {
if (requestGeneration !== commandMenuGeneration) {
return;
}
commandHooks = mergeCommandHooks([]);
commandHooksRequest = null;
updateCommandMenu();
});
}
return;
}
var prefix = match[1].toLowerCase();
var activeBuffer = models.getActiveBuffer();
var isIrcBuffer = activeBuffer && activeBuffer.plugin === 'irc';
$scope.commandMenuLoading = false;
$scope.commandMenuMatches = commandHooks.filter(function(hook) {
return (!hook.serverCommand || isIrcBuffer) && hook.command.indexOf(prefix) === 0;
});
};
$scope.selectCommand = function(item) {
var suffix = item.args ? ' ' : '';
$scope.command = (item.insertion || ('/' + item.command.toLowerCase())) + suffix;
closeCommandMenu();
setTimeout(function() {
var inputNode = $scope.getInputNode();
inputNode.focus();
inputNode.setSelectionRange($scope.command.length, $scope.command.length);
}, 0);
};
var scrollCommandMenuSelection = function() {
setTimeout(function() {
var selected = document.getElementById(
$scope.inputId + '-command-' + $scope.commandMenuIndex
);
if (selected) {
selected.scrollIntoView({block: 'nearest'});
}
}, 0);
};
$scope.handleCommandMenuKey = function(event, code, inputNode) {
if (suppressCommandMenuKeypress && event.type === 'keypress' &&
(code === 9 || code === 13)) {
event.preventDefault();
return true;
}
if (!$scope.commandMenuOpen || event.type !== 'keydown' ||
document.activeElement !== inputNode || event.altKey ||
event.ctrlKey || event.metaKey) {
return false;
}
var count = $scope.commandMenuMatches.length;
if ((code === 38 || code === 40) && count > 0) {
var direction = code === 38 ? -1 : 1;
$scope.commandMenuIndex = ($scope.commandMenuIndex + direction + count) % count;
scrollCommandMenuSelection();
event.preventDefault();
return true;
}
if ((code === 9 || code === 13) && count > 0 && !event.shiftKey) {
$scope.selectCommand($scope.commandMenuMatches[$scope.commandMenuIndex]);
suppressCommandMenuKeypress = true;
setTimeout(function() { suppressCommandMenuKeypress = false; }, 0);
event.preventDefault();
return true;
}
if (code === 27) {
closeCommandMenu();
event.preventDefault();
return true;
}
return false;
};
var removeCommandMenuDisconnect = $rootScope.$on('relayDisconnect', function() {
commandMenuGeneration++;
commandHooks = null;
commandHooksRequest = null;
closeCommandMenu();
});
$scope.$on('$destroy', removeCommandMenuDisconnect);