diff options
Diffstat (limited to 'assets/js/core')
-rw-r--r-- | assets/js/core/base.js | 54 | ||||
-rw-r--r-- | assets/js/core/bootstrap.js | 1 | ||||
-rw-r--r-- | assets/js/core/dom.js | 18 | ||||
-rw-r--r-- | assets/js/core/utils.js | 55 |
4 files changed, 111 insertions, 17 deletions
diff --git a/assets/js/core/base.js b/assets/js/core/base.js index d304d8bd..a4fd00ac 100644 --- a/assets/js/core/base.js +++ b/assets/js/core/base.js @@ -37,12 +37,16 @@ KB.onChange = function (selector, callback) { this.listeners.changes[selector] = callback; }; -KB.onKey = function (key, callback) { - this.listeners.keys[key] = callback; +KB.onKey = function (key, callback, ignoreInputField) { + this.listeners.keys[key] = { + 'callback': callback, + 'ignoreInputField': ignoreInputField || false + }; }; KB.listen = function () { var self = this; + var keysQueue = []; function onClick(e) { for (var selector in self.listeners.clicks) { @@ -61,28 +65,48 @@ KB.listen = function () { } } - function onKeypress(e) { - var key = (typeof e.which === 'number') ? e.which : e.keyCode; - var element = e.target; + function onKeyPressed(e) { + var key = KB.utils.getKey(e); + var isInputField = KB.utils.isInputField(e); - if (element.tagName === 'INPUT' || - element.tagName === 'SELECT' || - element.tagName === 'TEXTAREA' || - element.isContentEditable) { - return; + if (! isInputField || ['Escape', 'Meta', 'Enter', 'Control'].indexOf(key) !== -1) { + keysQueue.push(key); } - for (var keyMap in self.listeners.keys) { - if (self.listeners.keys.hasOwnProperty(keyMap) && key === parseInt(keyMap)) { - e.preventDefault(); - self.listeners.keys[key](e); + if (keysQueue.length > 0) { + var reset = true; + + for (var combination in self.listeners.keys) { + if (self.listeners.keys.hasOwnProperty(combination)) { + var keyboardListener = self.listeners.keys[combination]; + var sequence = combination.split('+'); + + if (KB.utils.arraysIdentical(keysQueue, sequence)) { + if (isInputField && !keyboardListener.ignoreInputField) { + keysQueue = []; + return; + } + + e.preventDefault(); + e.stopPropagation(); + keysQueue = []; + keyboardListener.callback(e); + break; + } else if (KB.utils.arraysStartsWith(keysQueue, sequence)) { + reset = false; + } + } + } + + if (reset) { + keysQueue = []; } } } document.addEventListener('click', onClick, false); document.addEventListener('change', onChange, false); - document.addEventListener('keypress', onKeypress, false); + window.addEventListener('keydown', onKeyPressed, false); }; KB.component = function (name, object) { diff --git a/assets/js/core/bootstrap.js b/assets/js/core/bootstrap.js index 3af086f1..7baa9e76 100644 --- a/assets/js/core/bootstrap.js +++ b/assets/js/core/bootstrap.js @@ -2,4 +2,5 @@ document.addEventListener('DOMContentLoaded', function () { KB.render(); KB.listen(); + KB.keyboardShortcuts(); }); diff --git a/assets/js/core/dom.js b/assets/js/core/dom.js index 2c44de58..84bdade2 100644 --- a/assets/js/core/dom.js +++ b/assets/js/core/dom.js @@ -4,10 +4,12 @@ KB.dom = function (tag) { var element = typeof tag === 'string' ? document.createElement(tag) : tag; this.attr = function (attribute, value) { - if (value !== null) { + if (value !== null && typeof value !== 'undefined') { element.setAttribute(attribute, value); + return this; + } else { + return element.getAttribute(attribute); } - return this; }; this.data = function (attribute, value) { @@ -175,3 +177,15 @@ KB.find = function (selector) { return null; }; + +KB.exists = function (selector) { + return !!document.querySelector(selector); +}; + +KB.focus = function (selector) { + var element = document.querySelector(selector); + + if (element) { + return element.focus(); + } +}; diff --git a/assets/js/core/utils.js b/assets/js/core/utils.js index e8e74b17..4d0f8847 100644 --- a/assets/js/core/utils.js +++ b/assets/js/core/utils.js @@ -32,3 +32,58 @@ KB.utils.getSelectionPosition = function (element) { selectionEnd: selectionEnd }; }; + +KB.utils.arraysIdentical = function (a, b) { + var i = a.length; + + if (i !== b.length) { + return false; + } + + while (i--) { + if (a[i] !== b[i]) { + return false; + } + } + + return true; +}; + +KB.utils.arraysStartsWith = function (array1, array2) { + var length = Math.min(array1.length, array2.length); + + for (var i = 0; i < length; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + + return true; +}; + +KB.utils.isInputField = function (event) { + var element = event.target; + + return !!(element.tagName === 'INPUT' || + element.tagName === 'SELECT' || + element.tagName === 'TEXTAREA' || + element.isContentEditable); +}; + +KB.utils.getKey = function (e) { + var mapping = { + 'Esc': 'Escape', + 'Up': 'ArrowUp', + 'Down': 'ArrowDown', + 'Left': 'ArrowLeft', + 'Right': 'ArrowRight' + }; + + for (var key in mapping) { + if (mapping.hasOwnProperty(key) && key === e.key) { + return mapping[key]; + } + } + + return e.key; +}; |