shortcuts WIP

This commit is contained in:
zadam 2019-11-19 20:53:04 +01:00
parent 0ae9c8da17
commit 4bd7438fca
12 changed files with 160 additions and 63 deletions

6
package-lock.json generated
View File

@ -3112,9 +3112,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"ejs": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.2.tgz",
"integrity": "sha512-rHGwtpl67oih3xAHbZlpw5rQAt+YV1mSCu2fUZ9XNrfaGEhom7E+AUiMci+ByP4aSfuAWx7hE0BPuJLMrpXwOw=="
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.3.tgz",
"integrity": "sha512-NtMNsdpaCF23gvHItgT37gzrpzckzs7KB7mg+YH1GMSG/5iZRq1BeWzAhEAJVagfM7nCQDnh/C51j/L2qjZmnA=="
},
"electron": {
"version": "6.0.12",

View File

@ -29,7 +29,7 @@
"csurf": "1.10.0",
"dayjs": "1.8.17",
"debug": "4.1.1",
"ejs": "2.7.2",
"ejs": "2.7.3",
"electron-debug": "3.0.1",
"electron-dl": "1.14.0",
"electron-find": "1.0.6",

View File

@ -4,6 +4,7 @@ import zoomService from "./zoom.js";
import protectedSessionService from "./protected_session.js";
import searchNotesService from "./search_notes.js";
import treeService from "./tree.js";
import server from "./server.js";
const NOTE_REVISIONS = "../dialogs/note_revisions.js";
const OPTIONS = "../dialogs/options.js";
@ -208,6 +209,43 @@ function registerEntrypoints() {
}
class KeyboardAction {
constructor(params) {
/** @property {string} */
this.optionName = params.optionName;
/** @property {string[]} */
this.defaultShortcuts = Array.isArray(params.defaultShortcuts) ? params.defaultShortcuts : [params.defaultShortcuts];
/** @property {string[]} */
this.activeShortcuts = this.defaultShortcuts.slice();
/** @property {string} */
this.description = params.description;
}
addShortcut(shortcut) {
this.activeShortcuts.push(shortcut);
}
/**
* @param {string|string[]} shortcuts
*/
replaceShortcuts(shortcuts) {
this.activeShortcuts = Array.isArray(shortcuts) ? shortcuts : [shortcuts];
}
/** @return {KeyboardAction[]} */
static get allActions() {
return Object.keys(KeyboardAction)
.map(key => KeyboardAction[key])
.filter(obj => obj instanceof KeyboardAction);
}
}
server.get('keyboard-actions').then(actions => {
for (const action of actions) {
}
});
export default {
registerEntrypoints
}

View File

@ -13,6 +13,10 @@ class Options {
return this.arr[key];
}
getNames() {
return Object.keys(this.arr);
}
getJson(key) {
try {
return JSON.parse(this.arr[key]);

View File

@ -58,7 +58,7 @@ class Sidebar {
import("../widgets/note_revisions.js"),
import("../widgets/attributes.js"),
import("../widgets/what_links_here.js"),
import("../widgets/similar_notes.js"),
import("../widgets/similar-notes.js"),
import("../widgets/edited_notes.js"),
import("../widgets/calendar.js")
])).map(m => m.default);

View File

@ -18,7 +18,7 @@ class SimilarNotesWidget extends StandardWidget {
// remember which title was when we found the similar notes
this.title = this.ctx.note.title;
const similarNotes = await server.get('similar_notes/' + this.ctx.note.noteId);
const similarNotes = await server.get('similar-notes/' + this.ctx.note.noteId);
if (similarNotes.length === 0) {
this.$body.text("No similar notes found ...");

11
src/routes/api/keys.js Normal file
View File

@ -0,0 +1,11 @@
"use strict";
const keyboardActions = require('../../services/keyboard_actions');
async function getKeyboardActions() {
return await keyboardActions.getKeyboardActions();
}
module.exports = {
getKeyboardActions
};

View File

@ -5,7 +5,7 @@ const log = require('../../services/log');
const attributes = require('../../services/attributes');
// options allowed to be updated directly in options dialog
const ALLOWED_OPTIONS = [
const ALLOWED_OPTIONS = new Set([
'protectedSessionTimeout',
'noteRevisionSnapshotTimeInterval',
'zoomFactor',
@ -37,23 +37,32 @@ const ALLOWED_OPTIONS = [
'spellCheckLanguageCode',
'imageMaxWidthHeight',
'imageJpegQuality'
];
]);
async function getOptions() {
return await optionService.getOptionsMap(ALLOWED_OPTIONS);
const optionMap = await optionService.getOptionsMap();
const resultMap = {};
for (const optionName in optionMap) {
if (isAllowed(optionName)) {
resultMap[optionName] = optionMap[optionName];
}
}
return resultMap;
}
async function updateOption(req) {
const {name, value} = req.params;
if (!update(name, value)) {
if (!await update(name, value)) {
return [400, "not allowed option to change"];
}
}
async function updateOptions(req) {
for (const optionName in req.body) {
if (!update(optionName, req.body[optionName])) {
if (!await update(optionName, req.body[optionName])) {
// this should be improved
// it should return 400 instead of current 500, but at least it now rollbacks transaction
throw new Error(`${optionName} is not allowed to change`);
@ -62,7 +71,7 @@ async function updateOptions(req) {
}
async function update(name, value) {
if (!ALLOWED_OPTIONS.includes(name)) {
if (!isAllowed(name)) {
return false;
}
@ -97,6 +106,10 @@ async function getUserThemes() {
return ret;
}
function isAllowed(name) {
return ALLOWED_OPTIONS.has(name) || name.startsWith("keyboardShortcuts");
}
module.exports = {
getOptions,
updateOption,

View File

@ -33,7 +33,8 @@ const searchRoute = require('./api/search');
const dateNotesRoute = require('./api/date_notes');
const linkMapRoute = require('./api/link_map');
const clipperRoute = require('./api/clipper');
const similarNotesRoute = require('./api/similar_notes');
const similarNotesRoute = require('./api/similar-notes');
const keysRoute = require('./api/keys');
const log = require('../services/log');
const express = require('express');
@ -242,7 +243,9 @@ function register(app) {
route(POST, '/api/clipper/notes', clipperMiddleware, clipperRoute.createNote, apiResultHandler);
route(POST, '/api/clipper/open/:noteId', clipperMiddleware, clipperRoute.openNote, apiResultHandler);
apiRoute(GET, '/api/similar_notes/:noteId', similarNotesRoute.getSimilarNotes);
apiRoute(GET, '/api/similar-notes/:noteId', similarNotesRoute.getSimilarNotes);
apiRoute(GET, '/api/keyboard-actions', keysRoute.getKeyboardActions);
app.use('', router);
}

View File

@ -1,157 +1,191 @@
"use strict";
const optionService = require('./options');
const log = require('./log');
const ELECTRON = "electron";
const KEYBOARD_ACTIONS = [
const DEFAULT_KEYBOARD_ACTIONS = [
{
optionName: "JumpToNote",
actionName: "JumpToNote",
defaultShortcuts: ["mod+j"],
description: 'Open "Jump to note" dialog'
},
{
optionName: "MarkdownToHTML",
actionName: "MarkdownToHTML",
defaultShortcuts: ["mod+return"]
},
{
optionName: "NewTab",
actionName: "NewTab",
defaultShortcuts: ["mod+t"],
only: ELECTRON
},
{
optionName: "CloseTab",
actionName: "CloseTab",
defaultShortcuts: ["mod+w"],
only: ELECTRON
},
{
optionName: "NextTab",
actionName: "NextTab",
defaultShortcuts: ["mod+tab"],
only: ELECTRON
},
{
optionName: "PreviousTab",
actionName: "PreviousTab",
defaultShortcuts: ["mod+shift+tab"],
only: ELECTRON
},
{
optionName: "CreateNoteAfter",
actionName: "CreateNoteAfter",
defaultShortcuts: ["mod+o"]
},
{
optionName: "CreateNoteInto",
actionName: "CreateNoteInto",
defaultShortcuts: ["mod+p"]
},
{
optionName: "ScrollToActiveNote",
actionName: "ScrollToActiveNote",
defaultShortcuts: ["mod+."]
},
{
optionName: "CollapseTree",
actionName: "CollapseTree",
defaultShortcuts: ["alt+c"]
},
{
optionName: "RunSQL",
actionName: "RunSQL",
defaultShortcuts: ["mod+return"]
},
{
optionName: "FocusNote",
actionName: "FocusNote",
defaultShortcuts: ["return"]
},
{
optionName: "RunCurrentNote",
actionName: "RunCurrentNote",
defaultShortcuts: ["mod+return"]
},
{
optionName: "ClipboardCopy",
actionName: "ClipboardCopy",
defaultShortcuts: ["mod+c"]
},
{
optionName: "ClipboardPaste",
actionName: "ClipboardPaste",
defaultShortcuts: ["mod+v"]
},
{
optionName: "ClipboardCut",
actionName: "ClipboardCut",
defaultShortcuts: ["mod+x"]
},
{
optionName: "SelectAllNotesInParent",
actionName: "SelectAllNotesInParent",
defaultShortcuts: ["mod+a"]
},
{
optionName: "Undo",
actionName: "Undo",
defaultShortcuts: ["mod+z"]
},
{
optionName: "Redo",
actionName: "Redo",
defaultShortcuts: ["mod+y"]
},
{
optionName: "AddLinkToText",
actionName: "AddLinkToText",
defaultShortcuts: ["mod+l"]
},
{
optionName: "CloneNotesTo",
actionName: "CloneNotesTo",
defaultShortcuts: ["mod+shift+c"]
},
{
optionName: "MoveNotesTo",
actionName: "MoveNotesTo",
defaultShortcuts: ["mod+shift+c"]
},
{
optionName: "SearchNotes",
actionName: "SearchNotes",
defaultShortcuts: ["mod+s"]
},
{
optionName: "ShowAttributes",
actionName: "ShowAttributes",
defaultShortcuts: ["alt+a"]
},
{
optionName: "ShowHelp",
actionName: "ShowHelp",
defaultShortcuts: ["f1"]
},
{
optionName: "OpenSQLConsole",
actionName: "OpenSQLConsole",
defaultShortcuts: ["alt+o"]
},
{
optionName: "BackInNoteHistory",
actionName: "BackInNoteHistory",
defaultShortcuts: ["alt+left"]
},
{
optionName: "ForwardInNoteHistory",
actionName: "ForwardInNoteHistory",
defaultShortcuts: ["alt+right"]
},
{
optionName: "ToggleZenMode",
actionName: "ToggleZenMode",
defaultShortcuts: ["alt+m"]
},
{
optionName: "InsertDateTime",
actionName: "InsertDateTime",
defaultShortcuts: ["alt+t"]
},
{
optionName: "ReloadApp",
actionName: "ReloadApp",
defaultShortcuts: ["f5", "mod+r"]
},
{
optionName: "OpenDevTools",
actionName: "OpenDevTools",
defaultShortcuts: ["mod+shift+i"]
},
{
optionName: "FindInText",
actionName: "FindInText",
defaultShortcuts: ["mod+f"]
},
{
optionName: "ToggleFullscreen",
actionName: "ToggleFullscreen",
defaultShortcuts: ["f11"]
},
{
optionName: "ZoomOut",
actionName: "ZoomOut",
defaultShortcuts: ["mod+-"]
},
{
optionName: "ZoomIn",
actionName: "ZoomIn",
defaultShortcuts: ["mod+="]
}
];
async function getKeyboardActions() {
const actions = JSON.parse(JSON.stringify(DEFAULT_KEYBOARD_ACTIONS));
for (const action of actions) {
action.effectiveShortcuts = action.defaultShortcuts.slice();
}
for (const option of await optionService.getOptions()) {
if (option.name.startsWith('keyboardShortcuts')) {
const actionName = option.name.substr(17);
const action = actions.find(ea => ea.actionName === actionName);
if (action) {
try {
action.effectiveShortcuts = JSON.parse(option.value);
}
catch (e) {
log.error(`Could not parse shortcuts for action ${actionName}`);
}
}
else {
log.info(`Keyboard action ${actionName} not found.`);
}
}
}
}
module.exports = {
KEYBOARD_ACTIONS
DEFAULT_KEYBOARD_ACTIONS,
getKeyboardActions
};

View File

@ -61,18 +61,12 @@ async function createOption(name, value, isSynced) {
}).save();
}
async function getOptions(allowedOptions) {
let options = await require('./repository').getEntities("SELECT * FROM options ORDER BY name");
if (allowedOptions) {
options = options.filter(opt => allowedOptions.includes(opt.name));
}
return options;
async function getOptions() {
return await require('./repository').getEntities("SELECT * FROM options ORDER BY name");
}
async function getOptionsMap(allowedOptions) {
const options = await getOptions(allowedOptions);
async function getOptionsMap() {
const options = await getOptions();
return utils.toObject(options, opt => [opt.name, opt.value]);
}

View File

@ -100,7 +100,7 @@ async function initStartupOptions() {
}
function getKeyboardDefaultOptions() {
return keyboardActions.KEYBOARD_ACTIONS.map(ka => {
return keyboardActions.DEFAULT_KEYBOARD_ACTIONS.map(ka => {
return {
name: "keyboardShortcuts" + ka.optionName,
value: JSON.stringify(ka.defaultShortcuts),