mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-08-01 04:01:01 +00:00
make frontend keyboard shortcuts configurable
This commit is contained in:
parent
f788df99a0
commit
c43d33247d
7 changed files with 159 additions and 73 deletions
|
|
@ -136,6 +136,7 @@ TODO configure more restrictive Content-Security-Policy
|
|||
<script src="scripts/hint/hint-d.js"></script>
|
||||
<script src="scripts/inline-markdown/inline-markdown-d.js"></script>
|
||||
<script src="scripts/input-duration/input-duration-d.js"></script>
|
||||
<script src="scripts/keyboard-key-input/keyboard-key-input-d.js"></script>
|
||||
<script src="scripts/main/global-filters/duration-filter.js"></script>
|
||||
<script src="scripts/main/global-filters/number-to-month-filter.js"></script>
|
||||
<script src="scripts/main/global-services/git-log-s.js"></script>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
62
app/scripts/keyboard-key-input/keyboard-key-input-d.js
Normal file
62
app/scripts/keyboard-key-input/keyboard-key-input-d.js
Normal file
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
21
app/scripts/keyboard-key-input/keyboard-key-input-d.spec.js
Normal file
21
app/scripts/keyboard-key-input/keyboard-key-input-d.spec.js
Normal file
|
|
@ -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('<keyboard-key-input></keyboard-key-input>')(scope);
|
||||
scope.$digest();
|
||||
expect(true).toBe(true);
|
||||
}));
|
||||
});
|
||||
|
|
@ -255,43 +255,61 @@
|
|||
<section>
|
||||
<h2 class="md-title">Keyboard Shortcuts</h2>
|
||||
|
||||
<h3 class="md-caption">Global Shortcuts</h3>
|
||||
<section ng-if="vm.IS_ELECTRON">
|
||||
<h3 class="md-caption">Global Shortcuts (system wide)</h3>
|
||||
<md-input-container class="md-block">
|
||||
<label>Show/Hide Super Productivity</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
keyboard-key-input-control-keys="true"
|
||||
ng-model="r.keys.globalShowHide">
|
||||
</md-input-container>
|
||||
</section>
|
||||
|
||||
<h3 class="md-caption">Global Shortcuts (application wide)</h3>
|
||||
<md-input-container class="md-block">
|
||||
<label>Show/Hide Super Productivity</label>
|
||||
<label>Add new task</label>
|
||||
<input type="text"
|
||||
ng-model="r.keys.globalShowHide">
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.addNewTask">
|
||||
</md-input-container>
|
||||
|
||||
<h3 class="md-caption">Tasks</h3>
|
||||
<p>The following shortcuts apply for the currently selected task (via tab or mouse).</p>
|
||||
<p>The following shortcuts apply for the currently selected task (selected via tab or mouse).</p>
|
||||
<md-input-container class="md-block">
|
||||
<label>Edit title</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.taskEditTitle">
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label>Show/Hide Notes</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.taskToggleNotes">
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label>Edit estimation / time spent</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.taskOpenEstimationDialog">
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label>Toggle Done</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.taskToggleDone">
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label>Add sub task</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.taskAddSubTask">
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label>Delete Task</label>
|
||||
<input type="text"
|
||||
keyboard-key-input
|
||||
ng-model="r.keys.taskDelete">
|
||||
</md-input-container>
|
||||
|
||||
|
|
@ -303,28 +321,29 @@
|
|||
<div flex-gt-sm="50">
|
||||
<md-switch ng-model="r.config.isShortSyntaxEnabled"
|
||||
aria-label="Use short syntax (e.g. 'TaskTitleBla e:30m')">
|
||||
Use short syntax (e.g. 'TaskTitleBla e:30m') for task creation
|
||||
Use short syntax (e.g. 'TaskTitleBla t:30m') for task creation
|
||||
</md-switch>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container class="md-block">
|
||||
<div flex-gt-sm="50">
|
||||
<md-switch ng-model="r.config.isTakeABreakEnabled"
|
||||
aria-label="Enable take a break reminder">
|
||||
Enable take a break reminder
|
||||
</md-switch>
|
||||
</div>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block md-icon-float"
|
||||
ng-hide="!r.config.isTakeABreakEnabled">
|
||||
<label>Remind when I worked longer than X without a break</label>
|
||||
<ng-md-icon icon="timer"
|
||||
aria-label="timer"></ng-md-icon>
|
||||
<input type="text"
|
||||
input-duration
|
||||
ng-model="r.config.takeABreakMinWorkingTime">
|
||||
</md-input-container>
|
||||
|
||||
<section ng-if="vm.IS_ELECTRON">
|
||||
<md-input-container class="md-block">
|
||||
<div flex-gt-sm="50">
|
||||
<md-switch ng-model="r.config.isTakeABreakEnabled"
|
||||
aria-label="Enable take a break reminder">
|
||||
Enable take a break reminder
|
||||
</md-switch>
|
||||
</div>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block md-icon-float"
|
||||
ng-hide="!r.config.isTakeABreakEnabled">
|
||||
<label>Remind when I worked longer than X without a break</label>
|
||||
<ng-md-icon icon="timer"
|
||||
aria-label="timer"></ng-md-icon>
|
||||
<input type="text"
|
||||
input-duration
|
||||
ng-model="r.config.takeABreakMinWorkingTime">
|
||||
</md-input-container>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue