diff --git a/app/index.html b/app/index.html index 3841878396..e6c240ed99 100644 --- a/app/index.html +++ b/app/index.html @@ -136,6 +136,7 @@ TODO configure more restrictive Content-Security-Policy + diff --git a/app/scripts/_app.js b/app/scripts/_app.js index 12a06e9ffa..57438e3eed 100644 --- a/app/scripts/_app.js +++ b/app/scripts/_app.js @@ -82,7 +82,7 @@ InitGlobalModels(); } - function initGlobalShortcuts($document, Dialogs) { + function initGlobalShortcuts($document, Dialogs, $localStorage) { // we just use this single one as this usually does mess // up with the default browser shortcuts // better to use the global electron shortcuts here @@ -91,7 +91,7 @@ // only trigger if not in typing mode if (ev.target.tagName !== 'INPUT' && ev.target.tagName !== 'TEXTAREA') { // on star - if (ev.key === '*') { + if (ev.key === $localStorage.keys.addNewTask) { Dialogs('ADD_TASK', undefined, true); } } diff --git a/app/scripts/constants.js b/app/scripts/constants.js index 08d33c2824..5937ffa309 100644 --- a/app/scripts/constants.js +++ b/app/scripts/constants.js @@ -29,12 +29,13 @@ }, keys: { globalShowHide: 'Ctrl+Shift+X', - taskToggleDone: 'd', + addNewTask: '*', + taskEditTitle: 'Enter', taskToggleNotes: 'n', taskOpenEstimationDialog: 't', + taskToggleDone: 'd', taskAddSubTask: '+', - taskDelete: 'entf', - taskEditTitle: 'enter' + taskDelete: 'Delete' }, config: { isTakeABreakEnabled: false, diff --git a/app/scripts/keyboard-key-input/keyboard-key-input-d.js b/app/scripts/keyboard-key-input/keyboard-key-input-d.js new file mode 100644 index 0000000000..ef3ceabae4 --- /dev/null +++ b/app/scripts/keyboard-key-input/keyboard-key-input-d.js @@ -0,0 +1,62 @@ +/** + * @ngdoc directive + * @name superProductivity.directive:keyboardKeyInput + * @description + * # keyboardKeyInput + */ + +(function () { + 'use strict'; + + angular + .module('superProductivity') + .directive('keyboardKeyInput', keyboardKeyInput); + + /* @ngInject */ + function keyboardKeyInput($parse) { + return { + link: linkFn, + restrict: 'A' + }; + + function linkFn(scope, element, attrs) { + const modelGetter = $parse(attrs['ngModel']); + const modelSetter = modelGetter.assign; + + let prevVal = modelGetter(scope); + + element.on('keydown', ($event) => { + $event.preventDefault(); + $event.stopPropagation(); + //console.log($event); + //console.log(ngModelCtrl.$modelValue); + //console.log(attrs); + + // focus out on escape + if ($event.keyCode === 27 || $event.key === 'Escape') { + modelSetter(scope, prevVal); + element.blur(); + } + else { + if (attrs.keyboardKeyInputControlKeys) { + let val = ''; + if ($event.ctrlKey) { + val += 'Ctrl+'; + } + if ($event.altKey) { + val += 'Alt+'; + } + if ($event.shiftKey) { + val += 'Shift+'; + } + modelSetter(scope, val + $event.key); + } + else { + modelSetter(scope, $event.key); + } + } + scope.$apply(); + }); + } + } +})(); diff --git a/app/scripts/keyboard-key-input/keyboard-key-input-d.spec.js b/app/scripts/keyboard-key-input/keyboard-key-input-d.spec.js new file mode 100644 index 0000000000..16568bd0d2 --- /dev/null +++ b/app/scripts/keyboard-key-input/keyboard-key-input-d.spec.js @@ -0,0 +1,21 @@ +'use strict'; + +describe('Directive: keyboardKeyInput', function () { + + // load the directive's module + beforeEach(module('superProductivity')); + beforeEach(module('templates')); + + var element, + scope; + + beforeEach(inject(function ($rootScope) { + scope = $rootScope.$new(); + })); + + it('should do something', inject(function ($compile) { + element = $compile('')(scope); + scope.$digest(); + expect(true).toBe(true); + })); +}); \ No newline at end of file diff --git a/app/scripts/routes/settings/settings-c.html b/app/scripts/routes/settings/settings-c.html index 87d0027376..955cf8ce6b 100644 --- a/app/scripts/routes/settings/settings-c.html +++ b/app/scripts/routes/settings/settings-c.html @@ -255,43 +255,61 @@

Keyboard Shortcuts

-

Global Shortcuts

+
+

Global Shortcuts (system wide)

+ + + + +
+ +

Global Shortcuts (application wide)

- + + keyboard-key-input + ng-model="r.keys.addNewTask">

Tasks

-

The following shortcuts apply for the currently selected task (via tab or mouse).

+

The following shortcuts apply for the currently selected task (selected via tab or mouse).

@@ -303,28 +321,29 @@
- Use short syntax (e.g. 'TaskTitleBla e:30m') for task creation + Use short syntax (e.g. 'TaskTitleBla t:30m') for task creation
- -
- - Enable take a break reminder - -
-
- - - - - - +
+ +
+ + Enable take a break reminder + +
+
+ + + + + +
diff --git a/app/scripts/task-list/task-list-d.js b/app/scripts/task-list/task-list-d.js index 099e4e68a1..9ca83ae005 100644 --- a/app/scripts/task-list/task-list-d.js +++ b/app/scripts/task-list/task-list-d.js @@ -12,7 +12,7 @@ class TaskListCtrl { /* @ngInject */ - constructor(Dialogs, $mdToast, $timeout, Tasks, EDIT_ON_CLICK_TOGGLE_EV, $scope, ShortSyntax, $element, Jira) { + constructor(Dialogs, $localStorage, $mdToast, $timeout, Tasks, EDIT_ON_CLICK_TOGGLE_EV, $scope, ShortSyntax, $element, Jira) { this.Dialogs = Dialogs; this.$mdToast = $mdToast; this.$timeout = $timeout; @@ -22,9 +22,11 @@ this.ShortSyntax = ShortSyntax; this.$element = $element; this.Jira = Jira; + this.$localStorage = $localStorage; this.lastFocusedTaskEl = undefined; this.boundHandleKeyPress = this.handleKeyPress.bind(this); + this.boundFocusLastTaskEl = this.focusLastFocusedTaskEl.bind(this); } $onDestroy() { @@ -113,7 +115,7 @@ estimateTime(task) { this.Dialogs('TIME_ESTIMATE', { task }) - .then(this.focusLastFocusedTaskEl, this.focusLastFocusedTaskEl); + .then(this.boundFocusLastTaskEl, this.boundFocusLastTaskEl); } deleteTask(task, $index) { @@ -188,48 +190,27 @@ taskEl = angular.element(taskEl); const task = this.lastFocusedTaskEl.scope().modelValue; - // only trigger if target is li - const USED_KEYS = [ - '+', - 'a', - 't', - 'n', - 'd' - ]; - const USED_KEY_CODES = [ - 46, - 13 - ]; + if ($event.key === this.$localStorage.keys.taskEditTitle) { + this.$scope.$broadcast(this.EDIT_ON_CLICK_TOGGLE_EV, task.id); + } + if ($event.key === this.$localStorage.keys.taskToggleNotes) { + task.showNotes = !task.showNotes; + } + if ($event.key === this.$localStorage.keys.taskOpenEstimationDialog) { + this.estimateTime(task); + } + if ($event.key === this.$localStorage.keys.taskToggleDone) { + task.isDone = !task.isDone; + } + if ($event.key === this.$localStorage.keys.taskAddSubTask) { + this.addSubTask(task); + } - if (USED_KEY_CODES.indexOf($event.keyCode) > -1 || USED_KEYS.indexOf($event.key) > -1) { - // + or a - if ($event.key === '+' || $event.key === 'a') { - this.addSubTask(task); - } - // t - if ($event.key === 't') { - this.estimateTime(task); - } - // n - if ($event.key === 'n') { - task.showNotes = !task.showNotes; - } - // d - if ($event.key === 'd') { - task.isDone = !task.isDone; - } - // entf - if ($event.keyCode === 46) { - this.deleteTask(task); - // don't propagate to next focused element - $event.preventDefault(); - $event.stopPropagation(); - } - // enter - if ($event.keyCode === 13) { - this.$scope.$broadcast(this.EDIT_ON_CLICK_TOGGLE_EV, task.id); - } - this.$scope.$apply(); + if ($event.key === this.$localStorage.keys.taskDelete) { + this.deleteTask(task); + // don't propagate to next focused element + $event.preventDefault(); + $event.stopPropagation(); } // moving items via shift+ctrl+keyUp/keyDown @@ -242,7 +223,6 @@ if ($event.keyCode === 38) { if (taskIndex > 0) { TaskListCtrl.moveItem(this.tasks, taskIndex, taskIndex - 1); - this.$scope.$apply(); // we need to manually re-add focus after timeout this.$timeout(() => { @@ -254,10 +234,12 @@ if ($event.keyCode === 40) { if (taskIndex < this.tasks.length - 1) { TaskListCtrl.moveItem(this.tasks, taskIndex, taskIndex + 1); - this.$scope.$apply(); } } } + + // finally apply + this.$scope.$apply(); } addSubTask(task) {