Source-Tag: v1.0.3 Manifest-SHA256: b7b09bf48f9e092ed8ad82f99c0319d6c3837d0a1549bd0cc4a374276c0f3896
147 lines
7.2 KiB
PHP
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);
|