From 0e5028acd30c80f5bfc153910bf31085e7a9a256 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 21 Nov 2019 21:12:07 +0100 Subject: [PATCH] support global shortcuts with global: prefix --- electron.js | 42 ++- package-lock.json | 213 +++++++++++++- package.json | 4 +- src/public/javascripts/desktop.js | 15 +- .../javascripts/services/entrypoints.js | 108 +++----- .../services/frontend_script_api.js | 4 - .../javascripts/services/keyboard_action.js | 261 ------------------ .../javascripts/services/keyboard_actions.js | 73 +++++ src/services/date_notes.js | 7 +- src/services/keyboard_actions.js | 61 ++-- src/services/options_init.js | 16 +- 11 files changed, 401 insertions(+), 403 deletions(-) delete mode 100644 src/public/javascripts/services/keyboard_action.js create mode 100644 src/public/javascripts/services/keyboard_actions.js diff --git a/electron.js b/electron.js index c2525639d..0db820e8e 100644 --- a/electron.js +++ b/electron.js @@ -8,6 +8,7 @@ const cls = require('./src/services/cls'); const url = require("url"); const port = require('./src/services/port'); const env = require('./src/services/env'); +const keyboardActionsService = require('./src/services/keyboard_actions'); const appIconService = require('./src/services/app_icon'); const windowStateKeeper = require('electron-window-state'); @@ -95,21 +96,42 @@ app.on('activate', () => { } }); +async function registerGlobalShortcuts() { + const allActions = await keyboardActionsService.getKeyboardActions(); + + for (const action of allActions) { + if (!action.effectiveShortcuts) { + continue; + } + + for (const shortcut of action.effectiveShortcuts) { + if (shortcut.startsWith('global:')) { + const translatedShortcut = shortcut.substr(7); + + const result = globalShortcut.register(translatedShortcut, cls.wrap(async () => { + // window may be hidden / not in focus + mainWindow.focus(); + + mainWindow.webContents.send('globalShortcut', action.actionName); + })); + + if (result) { + log.info(`Registered global shortcut ${translatedShortcut} for action ${action.actionName}`); + } + else { + log.info(`Could not register global shortcut ${translatedShortcut}`); + } + } + } + } +} + app.on('ready', async () => { app.setAppUserModelId('com.github.zadam.trilium'); mainWindow = await createMainWindow(); - const result = globalShortcut.register('CommandOrControl+Alt+P', cls.wrap(async () => { - // window may be hidden / not in focus - mainWindow.focus(); - - mainWindow.webContents.send('create-day-sub-note'); - })); - - if (!result) { - log.error("Could not register global shortcut CTRL+ALT+P"); - } + registerGlobalShortcuts(); }); app.on('will-quit', () => { diff --git a/package-lock.json b/package-lock.json index 29319ef7e..1c52fc218 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2680,14 +2680,22 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" }, "electron": { - "version": "8.0.0-beta.3", - "resolved": "https://registry.npmjs.org/electron/-/electron-8.0.0-beta.3.tgz", - "integrity": "sha512-MvzV3ApP5b+xGJXMPLaQkNSkggd0OixqRJvR1NvR/j4ZvvsEvL4K+ytT0PugvvOC7odgmsh2bmj0JCJZEg64eA==", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/electron/-/electron-6.0.12.tgz", + "integrity": "sha512-70ODZa1RP6K0gE9IV9YLCXPSyhLjXksCuYSSPb3MljbfwfHo5uE6X0CGxzm+54YuPdE2e7EPnWZxOOsJYrS5iQ==", "dev": true, "requires": { - "@electron/get": "^1.0.1", - "@types/node": "^12.0.12", + "@types/node": "^10.12.18", + "electron-download": "^4.1.0", "extract-zip": "^1.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz", + "integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==", + "dev": true + } } }, "electron-builder": { @@ -2837,6 +2845,57 @@ "unused-filename": "^1.0.0" } }, + "electron-download": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", + "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", + "dev": true, + "requires": { + "debug": "^3.0.0", + "env-paths": "^1.0.0", + "fs-extra": "^4.0.1", + "minimist": "^1.2.0", + "nugget": "^2.0.1", + "path-exists": "^3.0.0", + "rc": "^1.2.1", + "semver": "^5.4.1", + "sumchecker": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "electron-find": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/electron-find/-/electron-find-1.0.6.tgz", @@ -3266,6 +3325,12 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" }, + "env-paths": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", + "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -7071,6 +7136,32 @@ "boolbase": "~1.0.0" } }, + "nugget": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", + "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", + "dev": true, + "requires": { + "debug": "^2.1.3", + "minimist": "^1.1.0", + "pretty-bytes": "^1.0.2", + "progress-stream": "^1.1.0", + "request": "^2.45.0", + "single-line-log": "^1.1.2", + "throttleit": "0.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -8281,6 +8372,16 @@ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } + }, "process": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", @@ -8291,6 +8392,67 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", + "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", + "dev": true, + "requires": { + "speedometer": "~0.1.2", + "through2": "~0.2.3" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "through2": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", + "dev": true, + "requires": { + "readable-stream": "~1.1.9", + "xtend": "~2.1.1" + } + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "~0.4.0" + } + } + } + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -9010,6 +9172,15 @@ "moment": "^2.20.1" } }, + "single-line-log": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", + "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", + "dev": true, + "requires": { + "string-width": "^1.0.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -9104,6 +9275,12 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" }, + "speedometer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", + "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -9333,6 +9510,26 @@ "chalk": "^1.0.0" } }, + "sumchecker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz", + "integrity": "sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4=", + "dev": true, + "requires": { + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -9433,6 +9630,12 @@ "execa": "^0.7.0" } }, + "throttleit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", + "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", diff --git a/package.json b/package.json index 7c0b29751..0bef159cc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "start-server": "TRILIUM_ENV=dev node ./src/www", "start-electron": "TRILIUM_ENV=dev electron . --disable-gpu", "build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js", - "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/keyboard_action.js src/public/javascripts/services/frontend_script_api.js", + "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js", "build-docs": "npm run build-backend-docs && npm run build-frontend-docs" }, "dependencies": { @@ -77,7 +77,7 @@ "ws": "7.2.0" }, "devDependencies": { - "electron": "8.0.0-beta.3", + "electron": "6.0.12", "electron-builder": "22.1.0", "electron-installer-debian": "2.0.1", "electron-packager": "14.1.0", diff --git a/src/public/javascripts/desktop.js b/src/public/javascripts/desktop.js index 4af63e07d..ae3711b38 100644 --- a/src/public/javascripts/desktop.js +++ b/src/public/javascripts/desktop.js @@ -30,6 +30,7 @@ import cssLoader from './services/css_loader.js'; import dateNoteService from './services/date_notes.js'; import sidebarService from './services/sidebar.js'; import importService from './services/import.js'; +import keyboardActionService from "./services/keyboard_actions.js"; window.glob.isDesktop = utils.isDesktop; window.glob.isMobile = utils.isMobile; @@ -108,18 +109,8 @@ $("body").on("click", "a.external", function () { }); if (utils.isElectron()) { - require('electron').ipcRenderer.on('create-day-sub-note', async function(event) { - const todayNote = await dateNoteService.getTodayNote(); - const notePath = await treeService.getSomeNotePath(todayNote); - - const node = await treeService.expandToNote(notePath); - - await noteDetailService.openEmptyTab(false); - - await treeService.createNote(node, todayNote.noteId, 'into', { - type: "text", - isProtected: node.data.isProtected - }); + require('electron').ipcRenderer.on('globalShortcut', async function(event, actionName) { + keyboardActionService.triggerAction(actionName); }); } diff --git a/src/public/javascripts/services/entrypoints.js b/src/public/javascripts/services/entrypoints.js index 57601c6fe..ae5eb30b1 100644 --- a/src/public/javascripts/services/entrypoints.js +++ b/src/public/javascripts/services/entrypoints.js @@ -4,7 +4,9 @@ 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"; +import dateNoteService from "./date_notes.js"; +import noteDetailService from "./note_detail.js"; +import keyboardActionService from "./keyboard_actions.js"; const NOTE_REVISIONS = "../dialogs/note_revisions.js"; const OPTIONS = "../dialogs/options.js"; @@ -27,31 +29,31 @@ function registerEntrypoints() { jQuery.hotkeys.options.filterContentEditable = false; jQuery.hotkeys.options.filterTextInputs = false; - setActionHandler("AddLinkToText", () => import(ADD_LINK).then(d => d.showDialog())); + keyboardActionService.setActionHandler("AddLinkToText", () => import(ADD_LINK).then(d => d.showDialog())); const showJumpToNoteDialog = () => import(JUMP_TO_NOTE).then(d => d.showDialog()); $("#jump-to-note-dialog-button").on('click', showJumpToNoteDialog); - setActionHandler("JumpToNote", showJumpToNoteDialog); + keyboardActionService.setActionHandler("JumpToNote", showJumpToNoteDialog); const showRecentChanges = () => import(RECENT_CHANGES).then(d => d.showDialog()); $("#recent-changes-button").on('click', showRecentChanges); - setActionHandler("ShowRecentChanges", showRecentChanges); + keyboardActionService.setActionHandler("ShowRecentChanges", showRecentChanges); $("#enter-protected-session-button").on('click', protectedSessionService.enterProtectedSession); $("#leave-protected-session-button").on('click', protectedSessionService.leaveProtectedSession); $("#toggle-search-button").on('click', searchNotesService.toggleSearch); - setActionHandler('SearchNotes', searchNotesService.toggleSearch); + keyboardActionService.setActionHandler('SearchNotes', searchNotesService.toggleSearch); const $noteTabContainer = $("#note-tab-container"); const showAttributesDialog = () => import(ATTRIBUTES).then(d => d.showDialog()); $noteTabContainer.on("click", ".show-attributes-button", showAttributesDialog); - setActionHandler("ShowAttributes", showAttributesDialog); + keyboardActionService.setActionHandler("ShowAttributes", showAttributesDialog); const showNoteInfoDialog = () => import(NOTE_INFO).then(d => d.showDialog()); $noteTabContainer.on("click", ".show-note-info-button", showNoteInfoDialog); - setActionHandler("ShowNoteInfo", showNoteInfoDialog); + keyboardActionService.setActionHandler("ShowNoteInfo", showNoteInfoDialog); const showNoteRevisionsDialog = function() { if ($(this).hasClass("disabled")) { @@ -62,7 +64,7 @@ function registerEntrypoints() { }; $noteTabContainer.on("click", ".show-note-revisions-button", showNoteRevisionsDialog); - setActionHandler("ShowNoteRevisions", showNoteRevisionsDialog); + keyboardActionService.setActionHandler("ShowNoteRevisions", showNoteRevisionsDialog); const showNoteSourceDialog = function() { if ($(this).hasClass("disabled")) { @@ -73,33 +75,33 @@ function registerEntrypoints() { }; $noteTabContainer.on("click", ".show-source-button", showNoteSourceDialog); - setActionHandler("ShowNoteSource", showNoteSourceDialog); + keyboardActionService.setActionHandler("ShowNoteSource", showNoteSourceDialog); const showLinkMapDialog = () => import(LINK_MAP).then(d => d.showDialog()); $noteTabContainer.on("click", ".show-link-map-button", showLinkMapDialog); - setActionHandler("ShowLinkMap", showLinkMapDialog); + keyboardActionService.setActionHandler("ShowLinkMap", showLinkMapDialog); const showOptionsDialog = () => import(OPTIONS).then(d => d.showDialog()); $("#options-button").on('click', showOptionsDialog); - setActionHandler("ShowOptions", showOptionsDialog); + keyboardActionService.setActionHandler("ShowOptions", showOptionsDialog); const showHelpDialog = () => import(HELP).then(d => d.showDialog()); $("#show-help-button").on('click', showHelpDialog); - setActionHandler("ShowHelp", showHelpDialog); + keyboardActionService.setActionHandler("ShowHelp", showHelpDialog); const showSqlConsoleDialog = () => import(SQL_CONSOLE).then(d => d.showDialog()); $("#open-sql-console-button").on('click', showSqlConsoleDialog); - setActionHandler("ShowSQLConsole", showSqlConsoleDialog); + keyboardActionService.setActionHandler("ShowSQLConsole", showSqlConsoleDialog); $("#show-about-dialog-button").on('click', () => import(ABOUT).then(d => d.showDialog())); if (utils.isElectron()) { $("#history-navigation").show(); $("#history-back-button").on('click', window.history.back); - setActionHandler("BackInNoteHistory", window.history.back); + keyboardActionService.setActionHandler("BackInNoteHistory", window.history.back); $("#history-forward-button").on('click', window.history.forward); - setActionHandler("ForwardInNoteHistory", window.history.forward); + keyboardActionService.setActionHandler("ForwardInNoteHistory", window.history.forward); } // hide (toggle) everything except for the note content for zen mode @@ -109,9 +111,9 @@ function registerEntrypoints() { }; $("#toggle-zen-mode-button").on('click', toggleZenMode); - setActionHandler("ToggleZenMode", toggleZenMode); + keyboardActionService.setActionHandler("ToggleZenMode", toggleZenMode); - setActionHandler("InsertDateTime", () => { + keyboardActionService.setActionHandler("InsertDateTime", () => { const date = new Date(); const dateString = utils.formatDateTime(date); @@ -119,7 +121,7 @@ function registerEntrypoints() { }); $("#reload-frontend-button").on('click', utils.reloadApp); - setActionHandler("ReloadApp", utils.reloadApp); + keyboardActionService.setActionHandler("ReloadApp", utils.reloadApp); $("#open-dev-tools-button").toggle(utils.isElectron()); @@ -131,7 +133,7 @@ function registerEntrypoints() { }; $("#open-dev-tools-button").on('click', openDevTools); - setActionHandler("OpenDevTools", openDevTools); + keyboardActionService.setActionHandler("OpenDevTools", openDevTools); } let findInPage; @@ -153,7 +155,7 @@ function registerEntrypoints() { caseSelectedColor: 'var(--main-border-color)' }); - setActionHandler("FindInText", () => { + keyboardActionService.setActionHandler("FindInText", () => { if (!glob.activeDialog || !glob.activeDialog.is(":visible")) { findInPage.openFindWindow(); } @@ -173,7 +175,7 @@ function registerEntrypoints() { $("#toggle-fullscreen-button").on('click', toggleFullscreen); - setActionHandler("ToggleFullscreen", toggleFullscreen); + keyboardActionService.setActionHandler("ToggleFullscreen", toggleFullscreen); } else { // outside of electron this is handled by the browser @@ -181,8 +183,8 @@ function registerEntrypoints() { } if (utils.isElectron()) { - setActionHandler("ZoomOut", zoomService.decreaseZoomFactor); - setActionHandler("ZoomIn", zoomService.increaseZoomFactor); + keyboardActionService.setActionHandler("ZoomOut", zoomService.decreaseZoomFactor); + keyboardActionService.setActionHandler("ZoomIn", zoomService.increaseZoomFactor); } $(document).on('click', "a[data-action='note-revision']", async event => { @@ -197,7 +199,7 @@ function registerEntrypoints() { return false; }); - setActionHandler("CloneNotesTo", () => import(CLONE_TO).then(d => { + keyboardActionService.setActionHandler("CloneNotesTo", () => import(CLONE_TO).then(d => { const activeNode = treeService.getActiveNode(); const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode); @@ -207,62 +209,26 @@ function registerEntrypoints() { d.showDialog(noteIds); })); - setActionHandler("MoveNotesTo", () => import(MOVE_TO).then(d => { + keyboardActionService.setActionHandler("MoveNotesTo", () => import(MOVE_TO).then(d => { const activeNode = treeService.getActiveNode(); const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode); d.showDialog(selectedOrActiveNodes); })); -} + + keyboardActionService.setActionHandler("CreateNoteIntoDayNote", async () => { + const todayNote = await dateNoteService.getTodayNote();console.log(todayNote); + const notePath = await treeService.getSomeNotePath(todayNote); -class KeyboardAction { - constructor(params) { - /** @property {string} */ - this.actionName = params.actionName; - /** @property {string[]} */ - this.defaultShortcuts = params.defaultShortcuts; - /** @property {string[]} */ - this.effectiveShortcuts = params.effectiveShortcuts; - /** @property {string} */ - this.description = params.description; - } + const node = await treeService.expandToNote(notePath); - addShortcut(shortcut) { - this.effectiveShortcuts.push(shortcut); - } + await noteDetailService.openEmptyTab(false); - /** - * @param {string|string[]} shortcuts - */ - replaceShortcuts(shortcuts) { - this.effectiveShortcuts = Array.isArray(shortcuts) ? shortcuts : [shortcuts]; - } -} - -const keyboardActionRepo = {}; - -const keyboardActionsLoaded = server.get('keyboard-actions').then(actions => { - for (const action of actions) { - keyboardActionRepo[action.actionName] = new KeyboardAction(action); - } -}); - -function setActionHandler(actionName, handler) { - keyboardActionsLoaded.then(() => { - const action = keyboardActionRepo[actionName]; - - if (!action) { - throw new Error(`Cannot find keyboard action '${actionName}'`); - } - - action.handler = handler; - - for (const shortcut of action.effectiveShortcuts) { - if (shortcut) { - utils.bindGlobalShortcut(shortcut, handler); - } - } + await treeService.createNote(node, todayNote.noteId, 'into', { + type: "text", + isProtected: node.data.isProtected + }); }); } diff --git a/src/public/javascripts/services/frontend_script_api.js b/src/public/javascripts/services/frontend_script_api.js index 9d45a3677..ea6d2dd01 100644 --- a/src/public/javascripts/services/frontend_script_api.js +++ b/src/public/javascripts/services/frontend_script_api.js @@ -11,7 +11,6 @@ import dateNotesService from './date_notes.js'; import StandardWidget from '../widgets/standard_widget.js'; import ws from "./ws.js"; import hoistedNoteService from "./hoisted_note.js"; -import KeyboardAction from "./keyboard_action.js"; /** * This is the main frontend API interface for scripts. It's published in the local "api" object. @@ -41,9 +40,6 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte /** @property {StandardWidget} */ this.StandardWidget = StandardWidget; - /** @property {KeyboardAction} */ - this.KeyboardAction = KeyboardAction; - /** * Activates note in the tree and in the note detail. * diff --git a/src/public/javascripts/services/keyboard_action.js b/src/public/javascripts/services/keyboard_action.js deleted file mode 100644 index 2d74036ec..000000000 --- a/src/public/javascripts/services/keyboard_action.js +++ /dev/null @@ -1,261 +0,0 @@ -/** - * blaa vlaa - */ -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); - } -} - -const ELECTRON = 1; - -/** - * Open "Jump to note" dialog - * @static - */ -KeyboardAction.JumpToNote = new KeyboardAction({ - optionName: "JumpToNote", - defaultShortcuts: "mod+j", - description: 'Open "Jump to note" dialog' -}); - -/** @static */ -KeyboardAction.MarkdownToHTML = new KeyboardAction({ - optionName: "MarkdownToHTML", - defaultShortcuts: "mod+return" -}); - -/** @static */ -KeyboardAction.NewTab = new KeyboardAction({ - optionName: "NewTab", - defaultShortcuts: "mod+t", - only: ELECTRON -}); - -/** @static */ -KeyboardAction.CloseTab = new KeyboardAction({ - optionName: "CloseTab", - defaultShortcuts: "mod+w", - only: ELECTRON -}); - -/** @static */ -KeyboardAction.NextTab = new KeyboardAction({ - optionName: "NextTab", - defaultShortcuts: "mod+tab", - only: ELECTRON -}); - -/** @static */ -KeyboardAction.PreviousTab = new KeyboardAction({ - optionName: "PreviousTab", - defaultShortcuts: "mod+shift+tab", - only: ELECTRON -}); - -/** @static */ -KeyboardAction.CreateNoteAfter = new KeyboardAction({ - optionName: "CreateNoteAfter", - defaultShortcuts: "mod+o" -}); - -/** @static */ -KeyboardAction.CreateNoteInto = new KeyboardAction({ - optionName: "CreateNoteInto", - defaultShortcuts: "mod+p" -}); - -/** @static */ -KeyboardAction.ScrollToActiveNote = new KeyboardAction({ - optionName: "ScrollToActiveNote", - defaultShortcuts: "mod+." -}); - -/** @static */ -KeyboardAction.CollapseTree = new KeyboardAction({ - optionName: "CollapseTree", - defaultShortcuts: "alt+c" -}); - -/** @static */ -KeyboardAction.RunSQL = new KeyboardAction({ - optionName: "RunSQL", - defaultShortcuts: "mod+return" -}); - -/** @static */ -KeyboardAction.FocusNote = new KeyboardAction({ - optionName: "FocusNote", - defaultShortcuts: "return" -}); - -/** @static */ -KeyboardAction.RunCurrentNote = new KeyboardAction({ - optionName: "RunCurrentNote", - defaultShortcuts: "mod+return" -}); - -/** @static */ -KeyboardAction.ClipboardCopy = new KeyboardAction({ - optionName: "ClipboardCopy", - defaultShortcuts: "mod+c" -}); - -/** @static */ -KeyboardAction.ClipboardPaste = new KeyboardAction({ - optionName: "ClipboardPaste", - defaultShortcuts: "mod+v" -}); - -/** @static */ -KeyboardAction.ClipboardCut = new KeyboardAction({ - optionName: "ClipboardCut", - defaultShortcuts: "mod+x" -}); - -/** @static */ -KeyboardAction.SelectAllNotesInParent = new KeyboardAction({ - optionName: "SelectAllNotesInParent", - defaultShortcuts: "mod+a" -}); - -/** @static */ -KeyboardAction.Undo = new KeyboardAction({ - optionName: "Undo", - defaultShortcuts: "mod+z" -}); - -/** @static */ -KeyboardAction.Redo = new KeyboardAction({ - optionName: "Redo", - defaultShortcuts: "mod+y" -}); - -/** @static */ -KeyboardAction.AddLinkToText = new KeyboardAction({ - optionName: "AddLinkToText", - defaultShortcuts: "mod+l" -}); - -/** @static */ -KeyboardAction.CloneNotesTo = new KeyboardAction({ - optionName: "CloneNotesTo", - defaultShortcuts: "mod+shift+c" -}); - -/** @static */ -KeyboardAction.MoveNotesTo = new KeyboardAction({ - optionName: "MoveNotesTo", - defaultShortcuts: "mod+shift+c" -}); - -/** @static */ -KeyboardAction.SearchNotes = new KeyboardAction({ - optionName: "SearchNotes", - defaultShortcuts: "mod+s" -}); - -/** @static */ -KeyboardAction.ShowAttributes = new KeyboardAction({ - optionName: "ShowAttributes", - defaultShortcuts: "alt+a" -}); - -/** @static */ -KeyboardAction.ShowHelp = new KeyboardAction({ - optionName: "ShowHelp", - defaultShortcuts: "f1" -}); - -/** @static */ -KeyboardAction.OpenSQLConsole = new KeyboardAction({ - optionName: "OpenSQLConsole", - defaultShortcuts: "alt+o" -}); - -/** @static */ -KeyboardAction.BackInNoteHistory = new KeyboardAction({ - optionName: "BackInNoteHistory", - defaultShortcuts: "alt+left" -}); - -/** @static */ -KeyboardAction.ForwardInNoteHistory = new KeyboardAction({ - optionName: "ForwardInNoteHistory", - defaultShortcuts: "alt+right" -}); - -/** @static */ -KeyboardAction.ToggleZenMode = new KeyboardAction({ - optionName: "ToggleZenMode", - defaultShortcuts: "alt+m" -}); - -/** @static */ -KeyboardAction.InsertDateTime = new KeyboardAction({ - optionName: "InsertDateTime", - defaultShortcuts: "alt+t" -}); - -/** @static */ -KeyboardAction.ReloadApp = new KeyboardAction({ - optionName: "ReloadApp", - defaultShortcuts: ["f5", "mod+r"] -}); - -/** @static */ -KeyboardAction.OpenDevTools = new KeyboardAction({ - optionName: "OpenDevTools", - defaultShortcuts: "mod+shift+i" -}); - -/** @static */ -KeyboardAction.FindInText = new KeyboardAction({ - optionName: "FindInText", - defaultShortcuts: "mod+f" -}); - -/** @static */ -KeyboardAction.ToggleFullscreen = new KeyboardAction({ - optionName: "ToggleFullscreen", - defaultShortcuts: "f11" -}); - -/** @static */ -KeyboardAction.ZoomOut = new KeyboardAction({ - optionName: "ZoomOut", - defaultShortcuts: "mod+-" -}); - -/** @static */ -KeyboardAction.ZoomIn = new KeyboardAction({ - optionName: "ZoomIn", - defaultShortcuts: "mod+=" -}); - -export default KeyboardAction; \ No newline at end of file diff --git a/src/public/javascripts/services/keyboard_actions.js b/src/public/javascripts/services/keyboard_actions.js new file mode 100644 index 000000000..1cfd49244 --- /dev/null +++ b/src/public/javascripts/services/keyboard_actions.js @@ -0,0 +1,73 @@ +import server from "./server.js"; +import utils from "./utils.js"; + +class KeyboardAction { + constructor(params) { + /** @property {string} */ + this.actionName = params.actionName; + /** @property {string[]} */ + this.defaultShortcuts = params.defaultShortcuts; + /** @property {string[]} */ + this.effectiveShortcuts = params.effectiveShortcuts; + /** @property {string} */ + this.description = params.description; + } + + addShortcut(shortcut) { + this.effectiveShortcuts.push(shortcut); + } + + /** + * @param {string|string[]} shortcuts + */ + replaceShortcuts(shortcuts) { + this.effectiveShortcuts = Array.isArray(shortcuts) ? shortcuts : [shortcuts]; + } +} + +const keyboardActionRepo = {}; + +const keyboardActionsLoaded = server.get('keyboard-actions').then(actions => { + for (const action of actions) { + keyboardActionRepo[action.actionName] = new KeyboardAction(action); + } +}); + +function setActionHandler(actionName, handler) { + keyboardActionsLoaded.then(() => { + const action = keyboardActionRepo[actionName]; + + if (!action) { + throw new Error(`Cannot find keyboard action '${actionName}'`); + } + + action.handler = handler; + + for (const shortcut of action.effectiveShortcuts) { + if (shortcut) { + utils.bindGlobalShortcut(shortcut, handler); + } + } + }); +} + +async function triggerAction(actionName) { + await keyboardActionsLoaded; + + const action = keyboardActionRepo[actionName]; + + if (!action) { + throw new Error(`Cannot find action ${actionName}`); + } + + if (!action.handler) { + throw new Error(`Action ${actionName} has no handler`); + } + + await action.handler(); +} + +export default { + setActionHandler, + triggerAction +}; \ No newline at end of file diff --git a/src/services/date_notes.js b/src/services/date_notes.js index 270258576..7c37aeda7 100644 --- a/src/services/date_notes.js +++ b/src/services/date_notes.js @@ -13,12 +13,13 @@ const DATE_LABEL = 'dateNote'; const DAYS = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; const MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December']; -async function createNote(parentNoteId, noteTitle, noteText) { +async function createNote(parentNoteId, noteTitle) { return (await noteService.createNewNote({ parentNoteId: parentNoteId, title: noteTitle, - content: noteText, - isProtected: false + content: '', + isProtected: false, + type: 'text' })).note; } diff --git a/src/services/keyboard_actions.js b/src/services/keyboard_actions.js index 5c4788bee..b757406ba 100644 --- a/src/services/keyboard_actions.js +++ b/src/services/keyboard_actions.js @@ -19,7 +19,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "JumpToNote", - defaultShortcuts: ["Mod+J"], + defaultShortcuts: ["CommandOrControl+J"], description: 'Open "Jump to note" dialog' }, @@ -29,22 +29,22 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "NewTab", - defaultShortcuts: ["Mod+T"], + defaultShortcuts: ["CommandOrControl+T"], only: ELECTRON }, { actionName: "CloseTab", - defaultShortcuts: ["Mod+W"], + defaultShortcuts: ["CommandOrControl+W"], only: ELECTRON }, { actionName: "NextTab", - defaultShortcuts: ["Mod+Tab"], + defaultShortcuts: ["CommandOrControl+Tab"], only: ELECTRON }, { actionName: "PreviousTab", - defaultShortcuts: ["Mod+Shift+Tab"], + defaultShortcuts: ["CommandOrControl+Shift+Tab"], only: ELECTRON }, @@ -86,15 +86,20 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "CreateNoteAfter", - defaultShortcuts: ["Mod+O"] + defaultShortcuts: ["CommandOrControl+O"] }, { actionName: "CreateNoteInto", - defaultShortcuts: ["Mod+P"] + defaultShortcuts: ["CommandOrControl+P"] + }, + { + actionName: "CreateNoteIntoDayNote", + defaultShortcuts: ["global:CommandOrControl+Alt+P"], + description: "Create and open subnote of a current day note" }, { actionName: "ScrollToActiveNote", - defaultShortcuts: ["Mod+."] + defaultShortcuts: ["CommandOrControl+."] }, { actionName: "CollapseTree", @@ -106,26 +111,26 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "RunCurrentNote", - defaultShortcuts: ["Mod+return"] + defaultShortcuts: ["CommandOrControl+return"] }, { actionName: "ClipboardCopy", - defaultShortcuts: ["Mod+C"], + defaultShortcuts: ["CommandOrControl+C"], description: "Copy selected notes to the clipboard" }, { actionName: "ClipboardPaste", - defaultShortcuts: ["Mod+V"], + defaultShortcuts: ["CommandOrControl+V"], description: "Paste notes from the clipboard into active note" }, { actionName: "ClipboardCut", - defaultShortcuts: ["Mod+X"], + defaultShortcuts: ["CommandOrControl+X"], description: "Copy selected notes to the clipboard" }, { actionName: "SelectAllNotesInParent", - defaultShortcuts: ["Mod+A"], + defaultShortcuts: ["CommandOrControl+A"], description: "Select all notes from the current note level" }, { @@ -133,30 +138,30 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "Undo", - defaultShortcuts: ["Mod+Z"], + defaultShortcuts: ["CommandOrControl+Z"], description: "Undo last text operation (applicable on MacOS only)" }, { actionName: "Redo", - defaultShortcuts: ["Mod+Y"], + defaultShortcuts: ["CommandOrControl+Y"], description: "Undo last text operation (applicable on MacOS only)" }, { actionName: "AddLinkToText", - defaultShortcuts: ["Mod+L"], + defaultShortcuts: ["CommandOrControl+L"], description: "Open dialog to add link to the text" }, { actionName: "CloneNotesTo", - defaultShortcuts: ["Mod+Shift+C"] + defaultShortcuts: ["CommandOrControl+Shift+C"] }, { actionName: "MoveNotesTo", - defaultShortcuts: ["Mod+Shift+C"] + defaultShortcuts: ["CommandOrControl+Shift+C"] }, { actionName: "SearchNotes", - defaultShortcuts: ["Mod+S"] + defaultShortcuts: ["CommandOrControl+S"] }, { actionName: "ShowSQLConsole", @@ -164,7 +169,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "RunSQL", - defaultShortcuts: ["Mod+return"] + defaultShortcuts: ["CommandOrControl+return"] }, { actionName: "InsertDateTime", @@ -172,15 +177,15 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "ReloadApp", - defaultShortcuts: ["F5", "Mod+R"] + defaultShortcuts: ["F5", "CommandOrControl+R"] }, { actionName: "OpenDevTools", - defaultShortcuts: ["Mod+Shift+I"] + defaultShortcuts: ["CommandOrControl+Shift+I"] }, { actionName: "FindInText", - defaultShortcuts: ["Mod+F"] + defaultShortcuts: ["CommandOrControl+F"] }, { actionName: "ToggleFullscreen", @@ -192,22 +197,22 @@ const DEFAULT_KEYBOARD_ACTIONS = [ }, { actionName: "ZoomOut", - defaultShortcuts: ["Mod+-"] + defaultShortcuts: ["CommandOrControl+-"] }, { actionName: "ZoomIn", - defaultShortcuts: ["Mod+="] + defaultShortcuts: ["CommandOrControl+="] }, { actionName: "MarkdownToHTML", - defaultShortcuts: ["Mod+Return"] + defaultShortcuts: ["CommandOrControl+Return"] }, ]; if (process.platform === "darwin") { for (const action of DEFAULT_KEYBOARD_ACTIONS) { if (action.defaultShortcuts) { - action.defaultShortcuts = action.defaultShortcuts.map(shortcut => shortcut.replace("Mod", "Meta")); + action.defaultShortcuts = action.defaultShortcuts.map(shortcut => shortcut.replace("CommandOrControl", "Meta")); } } @@ -218,7 +223,7 @@ if (process.platform === "darwin") { else { for (const action of DEFAULT_KEYBOARD_ACTIONS) { if (action.defaultShortcuts) { - action.defaultShortcuts = action.defaultShortcuts.map(shortcut => shortcut.replace("Mod", "Ctrl")); + action.defaultShortcuts = action.defaultShortcuts.map(shortcut => shortcut.replace("CommandOrControl", "Ctrl")); } } } diff --git a/src/services/options_init.js b/src/services/options_init.js index 7f921b972..cb3f0aab8 100644 --- a/src/services/options_init.js +++ b/src/services/options_init.js @@ -100,13 +100,15 @@ async function initStartupOptions() { } function getKeyboardDefaultOptions() { - return keyboardActions.DEFAULT_KEYBOARD_ACTIONS.map(ka => { - return { - name: "keyboardShortcuts" + ka.actionName, - value: JSON.stringify(ka.defaultShortcuts), - isSynced: false - }; - }); + return keyboardActions.DEFAULT_KEYBOARD_ACTIONS + .filter(ka => !!ka.actionName) + .map(ka => { + return { + name: "keyboardShortcuts" + ka.actionName, + value: JSON.stringify(ka.defaultShortcuts), + isSynced: false + }; + }); } module.exports = {