diff --git a/package-lock.json b/package-lock.json
index c5624b0f7..08b25858a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "trilium",
- "version": "0.45.1",
+ "version": "0.45.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -586,11 +586,6 @@
"defer-to-connect": "^1.0.1"
}
},
- "@tokenizer/token": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz",
- "integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w=="
- },
"@tootallnate/once": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz",
@@ -611,7 +606,8 @@
"@types/debug": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
- "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
+ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==",
+ "dev": true
},
"@types/eslint": {
"version": "7.2.4",
@@ -3680,17 +3676,6 @@
"pend": "~1.2.0"
}
},
- "file-type": {
- "version": "16.0.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.0.0.tgz",
- "integrity": "sha512-0u4D11yDu0NXF+8qp1eiQ/6cOwPI7sbu9/bGzUOhlwzKbB9FYFivgTtsVPtlkXAakfByWjOsLp2/Jx927OVetg==",
- "requires": {
- "readable-web-to-node-stream": "^2.0.0",
- "strtok3": "^6.0.3",
- "token-types": "^2.0.0",
- "typedarray-to-buffer": "^3.1.5"
- }
- },
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -5882,11 +5867,6 @@
"pify": "^2.0.0"
}
},
- "peek-readable": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-3.1.0.tgz",
- "integrity": "sha512-KGuODSTV6hcgdZvDrIDBUkN0utcAVj1LL7FfGbM0viKTtCHmtZcuEJ+lGqsp0fTFkGqesdtemV2yUSMeyy3ddA=="
- },
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -6229,11 +6209,6 @@
"util-deprecate": "~1.0.1"
}
},
- "readable-web-to-node-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-2.0.0.tgz",
- "integrity": "sha512-+oZJurc4hXpaaqsN68GoZGQAQIA3qr09Or4fqEsargABnbe5Aau8hFn6ISVleT3cpY/0n/8drn7huyyEvTbghA=="
- },
"rechoir": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz",
@@ -7005,16 +6980,6 @@
"resolved": "https://registry.npmjs.org/striptags/-/striptags-3.1.1.tgz",
"integrity": "sha1-yMPn/db7S7OjKjt1LltePjgJPr0="
},
- "strtok3": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.0.4.tgz",
- "integrity": "sha512-rqWMKwsbN9APU47bQTMEYTPcwdpKDtmf1jVhHzNW2cL1WqAxaM9iBb9t5P2fj+RV2YsErUWgQzHD5JwV0uCTEQ==",
- "requires": {
- "@tokenizer/token": "^0.1.1",
- "@types/debug": "^4.1.5",
- "peek-readable": "^3.1.0"
- }
- },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -7293,15 +7258,6 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
- "token-types": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/token-types/-/token-types-2.0.0.tgz",
- "integrity": "sha512-WWvu8sGK8/ZmGusekZJJ5NM6rRVTTDO7/bahz4NGiSDb/XsmdYBn6a1N/bymUHuWYTWeuLUg98wUzvE4jPdCZw==",
- "requires": {
- "@tokenizer/token": "^0.1.0",
- "ieee754": "^1.1.13"
- }
- },
"tough-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
diff --git a/src/public/app/dialogs/export.js b/src/public/app/dialogs/export.js
index c3b8c8b18..b600ade80 100644
--- a/src/public/app/dialogs/export.js
+++ b/src/public/app/dialogs/export.js
@@ -3,6 +3,7 @@ import utils from "../services/utils.js";
import ws from "../services/ws.js";
import toastService from "../services/toast.js";
import treeCache from "../services/tree_cache.js";
+import openService from "../services/open.js";
const $dialog = $("#export-dialog");
const $form = $("#export-form");
@@ -73,9 +74,9 @@ $form.on('submit', () => {
function exportBranch(branchId, type, format, version) {
taskId = utils.randomString(10);
- const url = utils.getUrlForDownload(`api/notes/${branchId}/export/${type}/${format}/${version}/${taskId}`);
+ const url = openService.getUrlForDownload(`api/notes/${branchId}/export/${type}/${format}/${version}/${taskId}`);
- utils.download(url);
+ openService.download(url);
}
$('input[name=export-type]').on('change', function () {
@@ -133,4 +134,4 @@ ws.subscribeToMessages(async message => {
toastService.showPersistent(toast);
}
-});
\ No newline at end of file
+});
diff --git a/src/public/app/dialogs/note_revisions.js b/src/public/app/dialogs/note_revisions.js
index 39bdd2ea2..f5f3baaf9 100644
--- a/src/public/app/dialogs/note_revisions.js
+++ b/src/public/app/dialogs/note_revisions.js
@@ -3,6 +3,7 @@ import server from '../services/server.js';
import toastService from "../services/toast.js";
import appContext from "../services/app_context.js";
import libraryLoader from "../services/library_loader.js";
+import openService from "../services/open.js";
const $dialog = $("#note-revisions-dialog");
const $list = $("#note-revision-list");
@@ -121,11 +122,7 @@ async function setContentPane() {
const $downloadButton = $('');
- $downloadButton.on('click', () => {
- const url = utils.getUrlForDownload(`api/notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}/download`);
-
- utils.download(url);
- });
+ $downloadButton.on('click', () => openService.downloadNoteRevision(revisionItem.noteId, revisionItem.noteRevisionId));
$titleButtons.append($downloadButton);
diff --git a/src/public/app/dialogs/options/keyboard_shortcuts.js b/src/public/app/dialogs/options/keyboard_shortcuts.js
index 0d9133eec..2eaef5d98 100644
--- a/src/public/app/dialogs/options/keyboard_shortcuts.js
+++ b/src/public/app/dialogs/options/keyboard_shortcuts.js
@@ -81,7 +81,7 @@ export default class KeyboardShortcutsOptions {
.filter(shortcut => !!shortcut);
const opts = {};
- opts['keyboardShortcuts' + actionName] = JSON.stringify(shortcuts);
+ opts['keyboardShortcuts' + actionName.substr(0, 1).toUpperCase() + actionName.substr(1)] = JSON.stringify(shortcuts);
server.put('options', opts);
});
@@ -138,4 +138,4 @@ export default class KeyboardShortcutsOptions {
});
});
}
-}
\ No newline at end of file
+}
diff --git a/src/public/app/services/note_content_renderer.js b/src/public/app/services/note_content_renderer.js
index a4115d8d5..51638c735 100644
--- a/src/public/app/services/note_content_renderer.js
+++ b/src/public/app/services/note_content_renderer.js
@@ -1,9 +1,9 @@
import server from "./server.js";
-import utils from "./utils.js";
import renderService from "./render.js";
import protectedSessionService from "./protected_session.js";
import protectedSessionHolder from "./protected_session_holder.js";
import libraryLoader from "./library_loader.js";
+import openService from "./open.js";
async function getRenderedContent(note) {
const type = getRenderingType(note);
@@ -32,24 +32,11 @@ async function getRenderedContent(note) {
.css("max-width", "100%");
}
else if (type === 'file' || type === 'pdf') {
- function getFileUrl() {
- return utils.getUrlForDownload("api/notes/" + note.noteId + "/download");
- }
-
const $downloadButton = $('');
const $openButton = $('');
- $downloadButton.on('click', () => utils.download(getFileUrl()));
- $openButton.on('click', () => {
- if (utils.isElectron()) {
- const open = utils.dynamicRequire("open");
-
- open(getFileUrl(), {url: true});
- }
- else {
- window.location.href = getFileUrl();
- }
- });
+ $downloadButton.on('click', () => openService.downloadFileNote(note.noteId));
+ $openButton.on('click', () => openService.openFileNote(note.noteId));
// open doesn't work for protected notes since it works through browser which isn't in protected session
$openButton.toggle(!note.isProtected);
@@ -58,7 +45,7 @@ async function getRenderedContent(note) {
if (type === 'pdf') {
const $pdfPreview = $('');
- $pdfPreview.attr("src", utils.getUrlForDownload("api/notes/" + note.noteId + "/open"));
+ $pdfPreview.attr("src", openService.getUrlForDownload("api/notes/" + note.noteId + "/open"));
$rendered.append($pdfPreview);
}
diff --git a/src/public/app/services/open.js b/src/public/app/services/open.js
new file mode 100644
index 000000000..6054e223c
--- /dev/null
+++ b/src/public/app/services/open.js
@@ -0,0 +1,71 @@
+import utils from "./utils.js";
+import server from "./server.js";
+
+function getFileUrl(noteId) {
+ return getUrlForDownload("api/notes/" + noteId + "/download");
+}
+
+function download(url) {
+ if (utils.isElectron()) {
+ const remote = utils.dynamicRequire('electron').remote;
+
+ remote.getCurrentWebContents().downloadURL(url);
+ } else {
+ window.location.href = url;
+ }
+}
+
+function downloadFileNote(noteId) {
+ const url = getFileUrl(noteId) + '?' + Date.now(); // don't use cache
+
+ download(url);
+}
+
+async function openFileNote(noteId) {
+ if (utils.isElectron()) {
+ const resp = await server.post("notes/" + noteId + "/saveToTmpDir");
+
+ const electron = utils.dynamicRequire('electron');
+ const res = await electron.shell.openPath(resp.tmpFilePath);
+
+ if (res) {
+ // fallback in case there's no default application for this file
+ open(getFileUrl(noteId), {url: true});
+ }
+ }
+ else {
+ window.location.href = getFileUrl(noteId);
+ }
+}
+
+function downloadNoteRevision(noteId, noteRevisionId) {
+ const url = getUrlForDownload(`api/notes/${noteId}/revisions/${noteRevisionId}/download`);
+
+ download(url);
+}
+
+/**
+ * @param url - should be without initial slash!!!
+ */
+function getUrlForDownload(url) {
+ if (utils.isElectron()) {
+ // electron needs absolute URL so we extract current host, port, protocol
+ return getHost() + '/' + url;
+ }
+ else {
+ // web server can be deployed on subdomain so we need to use relative path
+ return url;
+ }
+}
+
+function getHost() {
+ const url = new URL(window.location.href);
+ return url.protocol + "//" + url.hostname + ":" + url.port;
+}
+
+export default {
+ downloadFileNote,
+ openFileNote,
+ downloadNoteRevision,
+ getUrlForDownload
+}
diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js
index 8e4e50a9f..aad45b500 100644
--- a/src/public/app/services/utils.js
+++ b/src/public/app/services/utils.js
@@ -105,24 +105,6 @@ function formatLabel(label) {
return str;
}
-function getHost() {
- const url = new URL(window.location.href);
- return url.protocol + "//" + url.hostname + ":" + url.port;
-}
-
-function download(url) {
- url += '?' + Date.now(); // don't use cache
-
- if (isElectron()) {
- const remote = dynamicRequire('electron').remote;
-
- remote.getCurrentWebContents().downloadURL(url);
- }
- else {
- window.location.href = url;
- }
-}
-
function toObject(array, fn) {
const obj = {};
@@ -294,20 +276,6 @@ async function clearBrowserCache() {
}
}
-/**
- * @param url - should be without initial slash!!!
- */
-function getUrlForDownload(url) {
- if (isElectron()) {
- // electron needs absolute URL so we extract current host, port, protocol
- return getHost() + '/' + url;
- }
- else {
- // web server can be deployed on subdomain so we need to use relative path
- return url;
- }
-}
-
function copySelectionToClipboard() {
const text = window.getSelection().toString();
if (navigator.clipboard) {
@@ -366,7 +334,6 @@ export default {
escapeHtml,
stopWatch,
formatLabel,
- download,
toObject,
randomString,
bindGlobalShortcut,
@@ -384,7 +351,6 @@ export default {
focusSavedElement,
isHtmlEmpty,
clearBrowserCache,
- getUrlForDownload,
normalizeShortcut,
copySelectionToClipboard,
isCKEditorInitialized,
diff --git a/src/public/app/widgets/type_widgets/file.js b/src/public/app/widgets/type_widgets/file.js
index 554d13564..fbf17e1f3 100644
--- a/src/public/app/widgets/type_widgets/file.js
+++ b/src/public/app/widgets/type_widgets/file.js
@@ -1,4 +1,5 @@
import utils from "../../services/utils.js";
+import openService from "../../services/open.js";
import server from "../../services/server.js";
import toastService from "../../services/toast.js";
import TypeWidget from "./type_widget.js";
@@ -73,24 +74,8 @@ export default class FileTypeWidget extends TypeWidget {
this.$uploadNewRevisionButton = this.$widget.find(".file-upload-new-revision");
this.$uploadNewRevisionInput = this.$widget.find(".file-upload-new-revision-input");
- this.$downloadButton.on('click', () => utils.download(this.getFileUrl()));
-
- this.$openButton.on('click', async () => {
- if (utils.isElectron()) {
- const resp = await server.post("notes/" + this.noteId + "/saveToTmpDir");
-
- const electron = utils.dynamicRequire('electron');
- const res = await electron.shell.openPath(resp.tmpFilePath);
-
- if (res) {
- // fallback in case there's no default application for this file
- open(this.getFileUrl(), {url: true});
- }
- }
- else {
- window.location.href = this.getFileUrl();
- }
- });
+ this.$downloadButton.on('click', () => openService.downloadFileNote(this.noteId));
+ this.$openButton.on('click', () => openService.openFileNote(this.noteId));
this.$uploadNewRevisionButton.on("click", () => {
this.$uploadNewRevisionInput.trigger("click");
@@ -146,14 +131,10 @@ export default class FileTypeWidget extends TypeWidget {
}
else if (note.mime === 'application/pdf') {
this.$pdfPreview.show();
- this.$pdfPreview.attr("src", utils.getUrlForDownload("api/notes/" + this.noteId + "/open"));
+ this.$pdfPreview.attr("src", openService.getUrlForDownload("api/notes/" + this.noteId + "/open"));
}
// open doesn't work for protected notes since it works through browser which isn't in protected session
this.$openButton.toggle(!note.isProtected);
}
-
- getFileUrl() {
- return utils.getUrlForDownload("api/notes/" + this.noteId + "/download");
- }
}
diff --git a/src/public/app/widgets/type_widgets/image.js b/src/public/app/widgets/type_widgets/image.js
index 5e5ffc567..c369536eb 100644
--- a/src/public/app/widgets/type_widgets/image.js
+++ b/src/public/app/widgets/type_widgets/image.js
@@ -1,6 +1,7 @@
import utils from "../../services/utils.js";
import toastService from "../../services/toast.js";
import server from "../../services/server.js";
+import openService from "../../services/open.js";
import TypeWidget from "./type_widget.js";
const TPL = `
@@ -64,7 +65,7 @@ class ImageTypeWidget extends TypeWidget {
this.$fileSize = this.$widget.find(".image-filesize");
this.$imageDownloadButton = this.$widget.find(".image-download");
- this.$imageDownloadButton.on('click', () => utils.download(this.getFileUrl()));
+ this.$imageDownloadButton.on('click', () => openService.downloadFileNote(this.noteId));
this.$copyToClipboardButton.on('click',() => {
this.$imageWrapper.attr('contenteditable','true');
@@ -145,10 +146,6 @@ class ImageTypeWidget extends TypeWidget {
selection.removeAllRanges();
selection.addRange(range);
}
-
- getFileUrl() {
- return utils.getUrlForDownload(`api/notes/${this.noteId}/download`);
- }
}
export default ImageTypeWidget
diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css
index ccf2c2541..31ab8d0d7 100644
--- a/src/public/stylesheets/style.css
+++ b/src/public/stylesheets/style.css
@@ -59,7 +59,7 @@ ul.fancytree-container {
font-size: x-large;
text-transform: none;
line-height: 1;
- content: "\ea1d";
+ content: "\e9b2";
position: relative;
top: -2px;
margin-right: 5px;
@@ -72,7 +72,7 @@ ul.fancytree-container {
.fancytree-node.fancytree-expanded .fancytree-expander:before {
font-family: 'boxicons' !important;
- content: "\ea17";
+ content: "\e9ac";
}
/** some common text styling for cssClass label */
diff --git a/src/services/keyboard_actions.js b/src/services/keyboard_actions.js
index 1db1ce37d..bb19dbeed 100644
--- a/src/services/keyboard_actions.js
+++ b/src/services/keyboard_actions.js
@@ -365,7 +365,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [
},
{
actionName: "openDevTools",
- defaultShortcuts: ["CommandOrControl+Shift+I"],
+ defaultShortcuts: isElectron ? ["CommandOrControl+Shift+I"] : [],
scope: "window"
},
{
@@ -408,13 +408,7 @@ for (const action of DEFAULT_KEYBOARD_ACTIONS) {
}
}
-let cachedActions = null;
-
function getKeyboardActions() {
- if (cachedActions) {
- return cachedActions;
- }
-
const actions = JSON.parse(JSON.stringify(DEFAULT_KEYBOARD_ACTIONS));
for (const action of actions) {
@@ -442,8 +436,6 @@ function getKeyboardActions() {
}
}
- cachedActions = actions;
-
return actions;
}