mirror of https://github.com/rancher/ui.git
211 lines
5.3 KiB
JavaScript
211 lines
5.3 KiB
JavaScript
;(function(Ember, $) {
|
|
var objectKeys = Object.keys || Ember.keys;
|
|
|
|
var MODIFIERS = {
|
|
'⇧': 16, shift: 16,
|
|
'⌥': 18, alt: 18, option: 18,
|
|
'⌃': 17, ctrl: 17, control: 17,
|
|
'⌘': 91, command: 91
|
|
};
|
|
|
|
var DEFINITIONS = {
|
|
backspace: 8, tab: 9, clear: 12,
|
|
enter: 13, 'return': 13,
|
|
esc: 27, escape: 27, space: 32,
|
|
left: 37, up: 38,
|
|
right: 39, down: 40,
|
|
del: 46, 'delete': 46,
|
|
home: 36, end: 35,
|
|
pageup: 33, pagedown: 34,
|
|
',': 188, '.': 190, '/': 191,
|
|
'`': 192, '-': 189, '=': 187,
|
|
';': 186, '\'': 222,
|
|
'[': 219, ']': 221, '\\': 220
|
|
};
|
|
|
|
for (var n = 1; n < 20; n++) DEFINITIONS['f'+n] = 111 + n;
|
|
|
|
function code(c) {
|
|
return DEFINITIONS[c] || c.toUpperCase().charCodeAt(0);
|
|
}
|
|
|
|
var ENABLED = true;
|
|
var PRESSED = {};
|
|
var PRESSED_MODS = {};
|
|
var SHORTCUTS = {};
|
|
|
|
function normalize(kc) {
|
|
switch (kc) {
|
|
case 93: case 224: return 91; // Firefox does ⌘ weird
|
|
case 61: return 187; // and `=`
|
|
case 173: return 189; // and `-`
|
|
default: return kc;
|
|
}
|
|
}
|
|
|
|
function isMod(kc) {
|
|
return kc === 16 || kc === 17 || kc === 18 || kc === 91;
|
|
}
|
|
|
|
function updatePressedMods(event, kc) {
|
|
if (event.shiftKey) PRESSED_MODS[16] = true;
|
|
if (event.ctrlKey) PRESSED_MODS[17] = true;
|
|
if (event.altKey) PRESSED_MODS[18] = true;
|
|
if (event.metaKey) PRESSED_MODS[91] = true;
|
|
}
|
|
|
|
function forEach(array, fn) {
|
|
for (var i = 0, len = array.length; i < len; i++) {
|
|
fn(array[i]);
|
|
}
|
|
}
|
|
|
|
function makeDispatch(router, filters) {
|
|
function triggerShortcut(def, event) {
|
|
var i, action, handler, infos;
|
|
|
|
if (!(infos = router.currentHandlerInfos)) return;
|
|
|
|
for (i = infos.length - 1; i >= 0; i--) {
|
|
handler = infos[i].handler;
|
|
|
|
if (handler.shortcuts && (action = handler.shortcuts[def.raw])) {
|
|
handler.send(action, event);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function filter(event) {
|
|
for (var i = 0; i < filters.length; i++) {
|
|
if (!filters[i](event)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return function dispatchShortcut(event) {
|
|
var kc = normalize(event.keyCode);
|
|
|
|
PRESSED[kc] = true;
|
|
|
|
if (isMod(kc)) {
|
|
PRESSED_MODS[kc] = true;
|
|
return;
|
|
}
|
|
|
|
updatePressedMods(event, kc);
|
|
|
|
if (!ENABLED) return;
|
|
if (!filter(event)) return;
|
|
if (!(kc in SHORTCUTS)) return;
|
|
|
|
forEach(SHORTCUTS[kc], function(def) {
|
|
if (!modsMatch(def)) return;
|
|
Ember.run(function() { triggerShortcut(def, event); });
|
|
});
|
|
};
|
|
}
|
|
|
|
function clear(event) {
|
|
var kc = normalize(event.keyCode);
|
|
if (PRESSED[kc]) PRESSED[kc] = undefined;
|
|
if (PRESSED_MODS[kc]) PRESSED_MODS[kc] = undefined;
|
|
}
|
|
|
|
function reset() {
|
|
PRESSED = {};
|
|
PRESSED_MODS = {};
|
|
}
|
|
|
|
function modsMatch(def) {
|
|
var mods = def.mods;
|
|
return mods[16] === PRESSED_MODS[16] && mods[17] === PRESSED_MODS[17] &&
|
|
mods[18] === PRESSED_MODS[18] && mods[91] === PRESSED_MODS[91];
|
|
}
|
|
|
|
function parse(spec) {
|
|
var parts = spec.replace(/\s+/g, '').split('+');
|
|
var kc = code(parts.pop());
|
|
var m, mods = {};
|
|
|
|
forEach(parts, function(part) {
|
|
if ((m = MODIFIERS[part])) mods[m] = true;
|
|
});
|
|
|
|
return { mods: mods, kc: kc, raw: spec };
|
|
}
|
|
|
|
function register(shortcuts) {
|
|
forEach(shortcuts, function(spec) {
|
|
var def = parse(spec);
|
|
if (!(def.kc in SHORTCUTS)) SHORTCUTS[def.kc] = [];
|
|
SHORTCUTS[def.kc].push(def);
|
|
});
|
|
}
|
|
|
|
var $doc = $(document);
|
|
var $win = $(window);
|
|
|
|
function targetIsNotInput(event) {
|
|
var tagName = event.target.tagName;
|
|
return (tagName !== 'INPUT') && (tagName !== 'SELECT') && (tagName !== 'TEXTAREA');
|
|
}
|
|
|
|
Ember.Shortcuts = Ember.Object.extend({
|
|
concatenatedProperties: ['filters'],
|
|
|
|
enable: function() { ENABLED = true; },
|
|
disable: function() { ENABLED = false; },
|
|
filters: [targetIsNotInput],
|
|
|
|
init: function() {
|
|
var router = this.get('router');
|
|
var filters = this.get('filters');
|
|
var dispatch = makeDispatch(router, filters);
|
|
|
|
$doc.on('keydown.ember-shortcuts', dispatch);
|
|
$doc.on('keyup.ember-shortcuts', clear);
|
|
$win.on('focus.ember-shortcuts', reset);
|
|
this.enable();
|
|
|
|
},
|
|
|
|
router: Ember.computed(function() {
|
|
var path = 'router:main';
|
|
return Ember.getOwner
|
|
? Ember.getOwner(this).lookup(path)._routerMicrolib
|
|
: this.container.lookup(path)._routerMicrolib;
|
|
}),
|
|
|
|
unbind: function() {
|
|
$doc.off('keydown.ember-shortcuts');
|
|
$doc.off('keyup.ember-shortcuts');
|
|
$win.off('focus.ember-shortcuts');
|
|
},
|
|
|
|
destroy: function() {
|
|
SHORTCUTS = {};
|
|
this.unbind();
|
|
}
|
|
});
|
|
|
|
Ember.Route.reopen({
|
|
mergedProperties: ['shortcuts'],
|
|
registerShortcuts: function() {
|
|
if (this.shortcuts) register(objectKeys(this.shortcuts));
|
|
}.on('init')
|
|
});
|
|
|
|
Ember.onLoad('Ember.Application', function(Application) {
|
|
Application.initializer({
|
|
name: 'Ember Shortcuts',
|
|
initialize: function() {
|
|
var application = arguments[1] || arguments[0];
|
|
application.register('shortcuts:main', Ember.Shortcuts);
|
|
application.inject('route', 'shortcuts', 'shortcuts:main');
|
|
application.inject('controller', 'shortcuts', 'shortcuts:main');
|
|
}
|
|
});
|
|
});
|
|
}(Ember, Ember.$));
|