Remove dependency on Mousetrap

This commit is contained in:
Frederic Guillot 2016-12-30 20:14:36 -05:00
parent e1344e3e44
commit ff79ec72c1
20 changed files with 348 additions and 202 deletions

View File

@ -6,13 +6,14 @@ New features:
* Add slideshow for images
* Add API calls to manage tags
* Offer the possibility to override internal formatter objects from plugins
* Open PDF attachments in browser tab (preview)
Improvements:
* Open PDF attachments in browser tab (preview)
* Handle username with dots in user mentions
* Replace Chosen jQuery plugin by custom UI component
* Rewrite UI component that change user/group roles
* Remove dependency on Mousetrap Javascript library
* Disable PageSpeed module from .htaccess if present
Bug fixes:

File diff suppressed because one or more lines are too long

View File

@ -2,14 +2,14 @@ KB.component('image-slideshow', function (containerElement, options) {
var currentImage;
function onKeyDown(e) {
switch (e.keyCode) {
case 27:
switch (KB.utils.getKey(e)) {
case 'Escape':
destroySlide();
break;
case 39:
case 'ArrowRight':
renderNextSlide();
break;
case 37:
case 'ArrowLeft':
renderPreviousSlide();
break;
}

View File

@ -1,4 +1,105 @@
// Open board selector: "b"
KB.onKey(98, function () {
KB.keyboardShortcuts = function () {
function goToLink (selector) {
var element = KB.find(selector);
if (element !== null) {
window.location = element.attr('href');
}
}
function submitForm() {
var forms = $("form");
if (forms.length == 1) {
forms.submit();
} else if (forms.length > 1) {
if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
$(document.activeElement).parents("form").submit();
} else if (_KB.get("Popover").isOpen()) {
$("#popover-container form").submit();
}
}
}
KB.onKey('?', function () {
_KB.get("Popover").open($("body").data("keyboard-shortcut-url"));
});
KB.onKey('Escape', function () {
if (! KB.exists('#suggest-menu')) {
_KB.get("Popover").close();
_KB.get("Dropdown").close();
}
});
KB.onKey('Meta+Enter', submitForm, true);
KB.onKey('Control+Enter', submitForm, true);
KB.onKey('b', function () {
KB.trigger('board.selector.open');
});
});
if (KB.exists('#board')) {
KB.onKey('c', function () {
_KB.get('BoardHorizontalScrolling').toggle();
});
KB.onKey('s', function () {
_KB.get('BoardCollapsedMode').toggle();
});
KB.onKey('n', function () {
_KB.get("Popover").open($("#board").data("task-creation-url"));
});
}
if (KB.exists('#task-view')) {
KB.onKey('e', function () {
_KB.get("Popover").open(KB.find('#task-view').data('editUrl'));
});
KB.onKey('c', function () {
_KB.get("Popover").open(KB.find('#task-view').data('commentUrl'));
});
KB.onKey('s', function () {
_KB.get("Popover").open(KB.find('#task-view').data('subtaskUrl'));
});
KB.onKey('l', function () {
_KB.get("Popover").open(KB.find('#task-view').data('internalLinkUrl'));
});
}
KB.onKey('f', function () {
KB.focus('#form-search');
});
KB.onKey('r', function () {
var reset = $(".filter-reset").data("filter");
var input = $("#form-search");
input.val(reset);
$("form.search").submit();
});
KB.onKey('v+o', function () {
goToLink('a.view-overview');
});
KB.onKey('v+b', function () {
goToLink('a.view-board');
});
KB.onKey('v+c', function () {
goToLink('a.view-calendar');
});
KB.onKey('v+l', function () {
goToLink('a.view-listing');
});
KB.onKey('v+g', function () {
goToLink('a.view-gantt');
});
};

View File

@ -2,22 +2,22 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
var componentElement, inputElement, inputHiddenElement;
function onKeyDown(e) {
switch (e.keyCode) {
case 27:
switch (KB.utils.getKey(e)) {
case 'Escape':
inputElement.value = '';
destroyDropdownMenu();
break;
case 38:
case 'ArrowUp':
e.preventDefault();
e.stopImmediatePropagation();
moveUp();
break;
case 40:
case 'ArrowDown':
e.preventDefault();
e.stopImmediatePropagation();
moveDown();
break;
case 13:
case 'Enter':
e.preventDefault();
e.stopImmediatePropagation();
insertSelectedItem();

View File

@ -1,21 +1,21 @@
KB.component('suggest-menu', function(containerElement, options) {
function onKeyDown(e) {
switch (e.keyCode) {
case 27:
switch (KB.utils.getKey(e)) {
case 'Escape':
destroy();
break;
case 38:
case 'ArrowUp':
e.preventDefault();
e.stopImmediatePropagation();
moveUp();
break;
case 40:
case 'ArrowDown':
e.preventDefault();
e.stopImmediatePropagation();
moveDown();
break;
case 13:
case 'Enter':
e.preventDefault();
e.stopImmediatePropagation();
insertSelectedItem();

View File

@ -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) {
if (! isInputField || ['Escape', 'Meta', 'Enter', 'Control'].indexOf(key) !== -1) {
keysQueue.push(key);
}
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;
}
for (var keyMap in self.listeners.keys) {
if (self.listeners.keys.hasOwnProperty(keyMap) && key === parseInt(keyMap)) {
e.preventDefault();
self.listeners.keys[key](e);
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) {

View File

@ -2,4 +2,5 @@
document.addEventListener('DOMContentLoaded', function () {
KB.render();
KB.listen();
KB.keyboardShortcuts();
});

View File

@ -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);
}
};
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();
}
};

View File

@ -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;
};

View File

@ -0,0 +1,113 @@
(function () {
var keyboardeventKeyPolyfill = {
polyfill: polyfill,
keys: {
3: 'Cancel',
6: 'Help',
8: 'Backspace',
9: 'Tab',
12: 'Clear',
13: 'Enter',
16: 'Shift',
17: 'Control',
18: 'Alt',
19: 'Pause',
20: 'CapsLock',
27: 'Escape',
28: 'Convert',
29: 'NonConvert',
30: 'Accept',
31: 'ModeChange',
32: ' ',
33: 'PageUp',
34: 'PageDown',
35: 'End',
36: 'Home',
37: 'ArrowLeft',
38: 'ArrowUp',
39: 'ArrowRight',
40: 'ArrowDown',
41: 'Select',
42: 'Print',
43: 'Execute',
44: 'PrintScreen',
45: 'Insert',
46: 'Delete',
48: ['0', ')'],
49: ['1', '!'],
50: ['2', '@'],
51: ['3', '#'],
52: ['4', '$'],
53: ['5', '%'],
54: ['6', '^'],
55: ['7', '&'],
56: ['8', '*'],
57: ['9', '('],
91: 'OS',
93: 'ContextMenu',
144: 'NumLock',
145: 'ScrollLock',
181: 'VolumeMute',
182: 'VolumeDown',
183: 'VolumeUp',
186: [';', ':'],
187: ['=', '+'],
188: [',', '<'],
189: ['-', '_'],
190: ['.', '>'],
191: ['/', '?'],
192: ['`', '~'],
219: ['[', '{'],
220: ['\\', '|'],
221: [']', '}'],
222: ["'", '"'],
224: 'Meta',
225: 'AltGraph',
246: 'Attn',
247: 'CrSel',
248: 'ExSel',
249: 'EraseEof',
250: 'Play',
251: 'ZoomOut'
}
};
// Function keys (F1-24).
var i;
for (i = 1; i < 25; i++) {
keyboardeventKeyPolyfill.keys[111 + i] = 'F' + i;
}
// Printable ASCII characters.
var letter = '';
for (i = 65; i < 91; i++) {
letter = String.fromCharCode(i);
keyboardeventKeyPolyfill.keys[i] = [letter.toLowerCase(), letter.toUpperCase()];
}
function polyfill() {
if (!('KeyboardEvent' in window) ||
'key' in KeyboardEvent.prototype) {
return false;
}
// Polyfill `key` on `KeyboardEvent`.
var proto = {
get: function (x) {
var key = keyboardeventKeyPolyfill.keys[this.which || this.keyCode];
if (Array.isArray(key)) {
key = key[+this.shiftKey];
}
return key;
}
};
Object.defineProperty(KeyboardEvent.prototype, 'key', proto);
return proto;
}
keyboardeventKeyPolyfill.polyfill();
})();

View File

@ -23,52 +23,15 @@ Kanboard.App.prototype.execute = function() {
if (typeof controller.focus === "function") {
controller.focus();
}
if (typeof controller.keyboardShortcuts === "function") {
controller.keyboardShortcuts();
}
}
}
this.focus();
this.keyboardShortcuts();
this.datePicker();
this.autoComplete();
this.tagAutoComplete();
};
Kanboard.App.prototype.keyboardShortcuts = function() {
var self = this;
// Submit form
Mousetrap.bindGlobal("mod+enter", function() {
var forms = $("form");
if (forms.length == 1) {
forms.submit();
} else if (forms.length > 1) {
if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
$(document.activeElement).parents("form").submit();
} else if (self.get("Popover").isOpen()) {
$("#popover-container form").submit();
}
}
});
// Close popover and dropdown
Mousetrap.bindGlobal("esc", function() {
if (! document.getElementById('suggest-menu')) {
self.get("Popover").close();
self.get("Dropdown").close();
}
});
// Show keyboard shortcut
Mousetrap.bind("?", function() {
self.get("Popover").open($("body").data("keyboard-shortcut-url"));
});
};
Kanboard.App.prototype.focus = function() {
// Auto-select input fields
$(document).on('focus', '.auto-select', function() {

View File

@ -2,16 +2,6 @@ Kanboard.BoardCollapsedMode = function(app) {
this.app = app;
};
Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts = function() {
var self = this;
if (self.app.hasId("board")) {
Mousetrap.bind("s", function() {
self.toggle();
});
}
};
Kanboard.BoardCollapsedMode.prototype.toggle = function() {
var self = this;
this.app.showLoadingIcon();

View File

@ -17,16 +17,6 @@ Kanboard.BoardHorizontalScrolling.prototype.listen = function() {
});
};
Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts = function() {
var self = this;
if (self.app.hasId("board")) {
Mousetrap.bind("c", function () {
self.toggle();
});
}
};
Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered = function() {
this.render();
};

View File

@ -17,13 +17,3 @@ Kanboard.BoardTask.prototype.listen = function() {
}
});
};
Kanboard.BoardTask.prototype.keyboardShortcuts = function() {
var self = this;
if (self.app.hasId("board")) {
Mousetrap.bind("n", function () {
self.app.get("Popover").open($("#board").data("task-creation-url"));
});
}
};

View File

@ -38,60 +38,3 @@ Kanboard.Search.prototype.listen = function() {
$("form.search").submit();
});
};
Kanboard.Search.prototype.goToView = function(label) {
var link = $(label);
if (link.length) {
window.location = link.attr('href');
}
};
Kanboard.Search.prototype.keyboardShortcuts = function() {
var self = this;
// Switch view mode for projects: go to the overview page
Mousetrap.bind("v o", function() {
self.goToView(".view-overview");
});
// Switch view mode for projects: go to the board
Mousetrap.bind("v b", function() {
self.goToView(".view-board");
});
// Switch view mode for projects: go to the calendar
Mousetrap.bind("v c", function() {
self.goToView(".view-calendar");
});
// Switch view mode for projects: go to the listing
Mousetrap.bind("v l", function() {
self.goToView(".view-listing");
});
// Switch view mode for projects: go to the gantt chart
Mousetrap.bind("v g", function() {
self.goToView(".view-gantt");
});
// Focus to the search field
Mousetrap.bind("f", function(e) {
e.preventDefault();
var input = document.getElementById("form-search");
if (input) {
input.focus();
}
});
// Reset to the search field
Mousetrap.bind("r", function(e) {
e.preventDefault();
var reset = $(".filter-reset").data("filter");
var input = $("#form-search");
input.val(reset);
$("form.search").submit();
});
};

View File

@ -2,29 +2,6 @@ Kanboard.Task = function(app) {
this.app = app;
};
Kanboard.Task.prototype.keyboardShortcuts = function() {
var taskView = $("#task-view");
var self = this;
if (this.app.hasId("task-view")) {
Mousetrap.bind("e", function() {
self.app.get("Popover").open(taskView.data("edit-url"));
});
Mousetrap.bind("c", function() {
self.app.get("Popover").open(taskView.data("comment-url"));
});
Mousetrap.bind("s", function() {
self.app.get("Popover").open(taskView.data("subtask-url"));
});
Mousetrap.bind("l", function() {
self.app.get("Popover").open(taskView.data("internal-link-url"));
});
}
};
Kanboard.Task.prototype.onPopoverOpened = function() {
var self = this;
var reloadingProjectId = 0;

File diff suppressed because one or more lines are too long

View File

@ -14,7 +14,6 @@
"jquery-ui": "^1.11.4",
"jqueryui-touch-punch": "*",
"jqueryui-timepicker-addon": "^1.6.3",
"mousetrap": "^1.5.3",
"font-awesome": "fontawesome#^4.7.0",
"d3": "~3.5.0",
"isMobile": "0.4.0",

View File

@ -48,8 +48,6 @@ var vendor = {
'bower_components/moment/min/moment.min.js',
'bower_components/fullcalendar/dist/fullcalendar.min.js',
'bower_components/fullcalendar/dist/locale-all.js',
'bower_components/mousetrap/mousetrap.min.js',
'bower_components/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js',
'bower_components/d3/d3.min.js',
'bower_components/c3/c3.min.js',
'bower_components/isMobile/isMobile.min.js',