From 42017fde5f2c2969761d87ee7c136a88aa17732d Mon Sep 17 00:00:00 2001
From: zadam
Date: Wed, 5 Feb 2020 22:08:45 +0100
Subject: [PATCH] refactored access to options on frontend
---
package-lock.json | 18 ++---
package.json | 4 +-
src/public/javascripts/desktop.js | 43 +----------
.../javascripts/dialogs/options/appearance.js | 3 +-
.../javascripts/dialogs/options/code_notes.js | 11 ++-
.../javascripts/dialogs/options/other.js | 4 --
.../javascripts/dialogs/options/sidebar.js | 2 -
.../javascripts/services/app_context.js | 23 ++++--
src/public/javascripts/services/clipboard.js | 2 +-
.../javascripts/services/entrypoints.js | 6 --
.../javascripts/services/hoisted_note.js | 27 ++-----
.../javascripts/services/load_results.js | 10 +++
src/public/javascripts/services/mime_types.js | 11 ++-
src/public/javascripts/services/options.js | 58 +++++----------
.../services/protected_session_holder.js | 19 ++---
.../javascripts/services/search_notes.js | 22 ++++--
.../javascripts/services/spell_check.js | 4 +-
src/public/javascripts/services/split.js | 23 ++----
.../javascripts/services/tab_context.js | 6 --
src/public/javascripts/services/tree_cache.js | 7 ++
src/public/javascripts/services/ws.js | 2 +-
src/public/javascripts/services/zoom.js | 72 +++++++++----------
src/public/javascripts/widgets/note_tree.js | 4 +-
src/public/javascripts/widgets/search_box.js | 19 +----
.../widgets/side_pane_container.js | 6 +-
.../javascripts/widgets/sidebar_toggle.js | 72 +++++++++++++++++++
.../javascripts/widgets/title_bar_buttons.js | 62 ++++++++--------
src/public/stylesheets/desktop.css | 14 ----
src/services/repository.js | 4 +-
src/services/sync.js | 11 +--
src/services/ws.js | 3 +
src/views/desktop.ejs | 6 --
32 files changed, 267 insertions(+), 311 deletions(-)
create mode 100644 src/public/javascripts/widgets/sidebar_toggle.js
diff --git a/package-lock.json b/package-lock.json
index b09696ac6..203d65d5d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2157,9 +2157,9 @@
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
},
"dayjs": {
- "version": "1.8.19",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.19.tgz",
- "integrity": "sha512-7kqOoj3oQSmqbvtvGFLU5iYqies+SqUiEGNT0UtUPPxcPYgY1BrkXR0Cq2R9HYSimBXN+xHkEN4Hi399W+Ovlg=="
+ "version": "1.8.20",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.20.tgz",
+ "integrity": "sha512-mH0MCDxw6UCGJYxVN78h8ugWycZAO8thkj3bW6vApL5tS0hQplIDdAQcmbvl7n35H0AKdCJQaArTrIQw2xt4Qg=="
},
"debug": {
"version": "4.1.1",
@@ -3782,9 +3782,9 @@
}
},
"file-type": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-14.0.0.tgz",
- "integrity": "sha512-+gxNvurlwHfTohZC6gqf0ybMl+cXYB9f1x++kw9AgKItdFx20J0fV9wCVR38a5/jphL5EUcusJ9tLYkPRtGHaw==",
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-14.1.0.tgz",
+ "integrity": "sha512-HfxnzrPH+LLClSAsno88/0frRtamu1XfqEP4IP/8RqBmqQnBQkemv3Udde0t53wZmrdOtc70aaR9WUHyQhjCUQ==",
"requires": {
"readable-web-to-node-stream": "^2.0.0",
"strtok3": "^6.0.0",
@@ -6859,9 +6859,9 @@
"integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
},
"node-abi": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.13.0.tgz",
- "integrity": "sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==",
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.14.0.tgz",
+ "integrity": "sha512-y54KGgEOHnRHlGQi7E5UiryRkH8bmksmQLj/9iLAjoje743YS+KaKB/sDYXgqtT0J16JT3c3AYJZNI98aU/kYg==",
"requires": {
"semver": "^5.4.1"
},
diff --git a/package.json b/package.json
index c7fbb170b..6c6a3faf8 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"electron-window-state": "5.0.3",
"express": "4.17.1",
"express-session": "1.17.0",
- "file-type": "14.0.0",
+ "file-type": "14.1.0",
"fs-extra": "8.1.0",
"helmet": "3.21.2",
"html": "1.0.0",
@@ -53,7 +53,7 @@
"jimp": "0.9.3",
"mime-types": "2.1.26",
"multer": "1.4.2",
- "node-abi": "2.13.0",
+ "node-abi": "2.14.0",
"open": "7.0.2",
"pngjs": "3.4.0",
"portscanner": "2.2.0",
diff --git a/src/public/javascripts/desktop.js b/src/public/javascripts/desktop.js
index 1e0c25730..f9bc52396 100644
--- a/src/public/javascripts/desktop.js
+++ b/src/public/javascripts/desktop.js
@@ -28,7 +28,7 @@ import dateNoteService from './services/date_notes.js';
import importService from './services/import.js';
import keyboardActionService from "./services/keyboard_actions.js";
import splitService from "./services/split.js";
-import optionService from "./services/options.js";
+import options from "./services/options.js";
import noteContentRenderer from "./services/note_content_renderer.js";
import appContext from "./services/app_context.js";
@@ -139,43 +139,4 @@ appContext.start();
noteTooltipService.setupGlobalTooltip();
-noteAutocompleteService.init();
-
-if (utils.isElectron()) {
- import("./services/spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck());
-}
-
-optionService.waitForOptions().then(options => {
- toggleSidebar('left', options.is('leftPaneVisible'));
- toggleSidebar('right', options.is('rightPaneVisible'));
-
- splitService.setupSplit(paneVisible.left, paneVisible.right);
-});
-
-const paneVisible = {};
-
-function toggleSidebar(side, show) {
- $(`#${side}-pane`).toggle(show);
- $(`#show-${side}-pane-button`).toggle(!show);
- $(`#hide-${side}-pane-button`).toggle(show);
-
- paneVisible[side] = show;
-}
-
-async function toggleAndSave(side, show) {
- toggleSidebar(side, show);
-
- await server.put(`options/${side}PaneVisible/` + show.toString());
-
- await optionService.reloadOptions();
-
- splitService.setupSplit(paneVisible.left, paneVisible.right);
-
- appContext.trigger('sidebarVisibilityChanged', {side, show});
-}
-
-$("#show-right-pane-button").on('click', () => toggleAndSave('right', true));
-$("#hide-right-pane-button").on('click', () => toggleAndSave('right', false));
-
-$("#show-left-pane-button").on('click', () => toggleAndSave('left', true));
-$("#hide-left-pane-button").on('click', () => toggleAndSave('left', false));
+noteAutocompleteService.init();
\ No newline at end of file
diff --git a/src/public/javascripts/dialogs/options/appearance.js b/src/public/javascripts/dialogs/options/appearance.js
index f478bbec5..484d63bc8 100644
--- a/src/public/javascripts/dialogs/options/appearance.js
+++ b/src/public/javascripts/dialogs/options/appearance.js
@@ -3,6 +3,7 @@ import utils from "../../services/utils.js";
import cssLoader from "../../services/css_loader.js";
import zoomService from "../../services/zoom.js";
import optionsService from "../../services/options.js";
+import appContext from "../../services/app_context.js";
const TPL = `
Settings on this options tab are saved automatically after each change.
@@ -107,7 +108,7 @@ export default class ApperanceOptions {
server.put('options/theme/' + newTheme);
});
- this.$zoomFactorSelect.on('change', () => { zoomService.setZoomFactorAndSave(this.$zoomFactorSelect.val()); });
+ this.$zoomFactorSelect.on('change', () => { appContext.trigger('setZoomFactorAndSave', {zoomFactor: this.$zoomFactorSelect.val()}); });
this.$nativeTitleBarSelect.on('change', () => {
const nativeTitleBarVisible = this.$nativeTitleBarSelect.val() === 'show' ? 'true' : 'false';
diff --git a/src/public/javascripts/dialogs/options/code_notes.js b/src/public/javascripts/dialogs/options/code_notes.js
index fc5544342..6ed785e10 100644
--- a/src/public/javascripts/dialogs/options/code_notes.js
+++ b/src/public/javascripts/dialogs/options/code_notes.js
@@ -1,6 +1,5 @@
-import server from "../../services/server.js";
import mimeTypesService from "../../services/mime_types.js";
-import optionsService from "../../services/options.js";
+import options from "../../services/options.js";
const TPL = `
Available MIME types in the dropdown
@@ -14,7 +13,7 @@ export default class CodeNotesOptions {
this.$mimeTypes = $("#options-mime-types");
}
- async optionsLoaded(options) {
+ async optionsLoaded() {
this.$mimeTypes.empty();
let idCtr = 1;
@@ -42,10 +41,8 @@ export default class CodeNotesOptions {
this.$mimeTypes.find("input:checked").each(
(i, el) => enabledMimeTypes.push($(el).attr("data-mime-type")));
- const opts = { codeNotesMimeTypes: JSON.stringify(enabledMimeTypes) };
+ await options.save('codeNotesMimeTypes', JSON.stringify(enabledMimeTypes));
- await server.put('options', opts);
-
- await optionsService.reloadOptions();
+ mimeTypesService.loadMimeTypes();
}
}
\ No newline at end of file
diff --git a/src/public/javascripts/dialogs/options/other.js b/src/public/javascripts/dialogs/options/other.js
index dc8bec45e..5d366eb3e 100644
--- a/src/public/javascripts/dialogs/options/other.js
+++ b/src/public/javascripts/dialogs/options/other.js
@@ -101,8 +101,6 @@ export default class ProtectedSessionOptions {
const eraseNotesAfterTimeInSeconds = this.$eraseNotesAfterTimeInSeconds.val();
server.put('options', { 'eraseNotesAfterTimeInSeconds': eraseNotesAfterTimeInSeconds }).then(() => {
- optionsService.reloadOptions();
-
toastService.showMessage("Options change have been saved.");
});
@@ -115,8 +113,6 @@ export default class ProtectedSessionOptions {
const protectedSessionTimeout = this.$protectedSessionTimeout.val();
server.put('options', { 'protectedSessionTimeout': protectedSessionTimeout }).then(() => {
- optionsService.reloadOptions();
-
toastService.showMessage("Options change have been saved.");
});
diff --git a/src/public/javascripts/dialogs/options/sidebar.js b/src/public/javascripts/dialogs/options/sidebar.js
index 9ba36d264..ff7eaeff1 100644
--- a/src/public/javascripts/dialogs/options/sidebar.js
+++ b/src/public/javascripts/dialogs/options/sidebar.js
@@ -104,8 +104,6 @@ export default class SidebarOptions {
});
await server.put('options', opts);
-
- optionsService.reloadOptions();
}
parseJsonSafely(str) {
diff --git a/src/public/javascripts/services/app_context.js b/src/public/javascripts/services/app_context.js
index 79c7a3e0e..f9ecd9b84 100644
--- a/src/public/javascripts/services/app_context.js
+++ b/src/public/javascripts/services/app_context.js
@@ -29,10 +29,12 @@ import bundleService from "./bundle.js";
import DialogEventComponent from "./dialog_events.js";
import Entrypoints from "./entrypoints.js";
import CalendarWidget from "../widgets/calendar.js";
-import optionsService from "./options.js";
+import options from "./options.js";
import utils from "./utils.js";
import treeService from "./tree.js";
import SidePaneContainer from "../widgets/side_pane_container.js";
+import ZoomService from "./zoom.js";
+import SidebarToggle from "../widgets/sidebar_toggle.js";
class AppContext {
constructor() {
@@ -45,7 +47,9 @@ class AppContext {
this.activeTabId = null;
}
- start() {
+ async start() {
+ options.load(await server.get('options'));
+
this.showWidgets();
this.loadTabs();
@@ -54,8 +58,6 @@ class AppContext {
}
async loadTabs() {
- const options = await optionsService.waitForOptions();
-
const openTabs = options.getJson('openTabs') || [];
await treeCache.initializedPromise;
@@ -186,14 +188,25 @@ class AppContext {
$centerPane.after(rightPaneContainer.render());
+ const sidebarToggleWidget = new SidebarToggle(this);
+
+ $centerPane.after(sidebarToggleWidget.render());
+
this.components = [
new Entrypoints(),
new DialogEventComponent(this),
...topPaneWidgets,
leftPaneContainer,
...centerPaneWidgets,
- rightPaneContainer
+ rightPaneContainer,
+ sidebarToggleWidget
];
+
+ if (utils.isElectron()) {
+ this.components.push(new ZoomService(this));
+
+ import("./spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck());
+ }
}
trigger(name, data, sync = false) {
diff --git a/src/public/javascripts/services/clipboard.js b/src/public/javascripts/services/clipboard.js
index 45489d6d4..eac84ab3a 100644
--- a/src/public/javascripts/services/clipboard.js
+++ b/src/public/javascripts/services/clipboard.js
@@ -70,7 +70,7 @@ function copy(nodes) {
function cut(nodes) {
clipboardBranchIds = nodes
- .filter(node => node.data.noteId !== hoistedNoteService.getHoistedNoteNoPromise())
+ .filter(node => node.data.noteId !== hoistedNoteService.getHoistedNoteId())
.filter(node => node.getParent().data.noteType !== 'search')
.map(node => node.key);
diff --git a/src/public/javascripts/services/entrypoints.js b/src/public/javascripts/services/entrypoints.js
index 0f9f23fab..0873eeb39 100644
--- a/src/public/javascripts/services/entrypoints.js
+++ b/src/public/javascripts/services/entrypoints.js
@@ -57,13 +57,7 @@ export default class Entrypoints extends Component {
});
}
- zoomOutListener() {
- zoomService.decreaseZoomFactor();
- }
- zoomInListener() {
- zoomService.increaseZoomFactor();
- }
async createNoteIntoDayNoteListener() {
const todayNote = await dateNoteService.getTodayNote();
diff --git a/src/public/javascripts/services/hoisted_note.js b/src/public/javascripts/services/hoisted_note.js
index d7d42ed9c..3d74d1d56 100644
--- a/src/public/javascripts/services/hoisted_note.js
+++ b/src/public/javascripts/services/hoisted_note.js
@@ -1,30 +1,16 @@
-import optionsService from './options.js';
-import server from "./server.js";
+import options from './options.js';
import appContext from "./app_context.js";
import treeService from "./tree.js";
-let hoistedNoteId = 'root';
-
-optionsService.waitForOptions().then(options => {
- hoistedNoteId = options.get('hoistedNoteId');
-});
-
-function getHoistedNoteNoPromise() {
- return hoistedNoteId;
-}
-
-async function getHoistedNoteId() {
- await optionsService.waitForOptions();
-
- return hoistedNoteId;
+function getHoistedNoteId() {
+ return options.get('hoistedNoteId');
}
async function setHoistedNoteId(noteId) {
- hoistedNoteId = noteId;
+ await options.save('hoistedNoteId', noteId);
- await server.put('options/hoistedNoteId/' + noteId);
-
- appContext.trigger('hoistedNoteChanged', {hoistedNoteId});
+ // FIXME - just use option load event
+ appContext.trigger('hoistedNoteChanged', {noteId});
}
async function unhoist() {
@@ -69,7 +55,6 @@ async function checkNoteAccess(notePath) {
export default {
getHoistedNoteId,
- getHoistedNoteNoPromise,
setHoistedNoteId,
unhoist,
isTopLevelNode,
diff --git a/src/public/javascripts/services/load_results.js b/src/public/javascripts/services/load_results.js
index 93ed405eb..eb2c410dd 100644
--- a/src/public/javascripts/services/load_results.js
+++ b/src/public/javascripts/services/load_results.js
@@ -14,6 +14,8 @@ export class LoadResults {
this.noteRevisions = [];
this.contentNoteIdToSourceId = [];
+
+ this.options = [];
}
addNote(noteId, sourceId) {
@@ -90,4 +92,12 @@ export class LoadResults {
return this.contentNoteIdToSourceId.find(l => l.noteId === noteId && l.sourceId !== sourceId);
}
+
+ addOption(name) {
+ this.options.push(name);
+ }
+
+ isOptionReloaded(name) {
+ this.options.includes(name);
+ }
}
\ No newline at end of file
diff --git a/src/public/javascripts/services/mime_types.js b/src/public/javascripts/services/mime_types.js
index 1b9229a10..a4919f03b 100644
--- a/src/public/javascripts/services/mime_types.js
+++ b/src/public/javascripts/services/mime_types.js
@@ -1,4 +1,4 @@
-import optionsService from "./options.js";
+import options from "./options.js";
const MIME_TYPES_DICT = [
{ default: true, title: "Plain text", mime: "text/plain" },
@@ -161,7 +161,7 @@ const MIME_TYPES_DICT = [
let mimeTypes = null;
-function loadMimeTypes(options) {
+function loadMimeTypes() {
mimeTypes = JSON.parse(JSON.stringify(MIME_TYPES_DICT)); // clone
const enabledMimeTypes = options.getJson('codeNotesMimeTypes')
@@ -172,16 +172,15 @@ function loadMimeTypes(options) {
}
}
-optionsService.addLoadListener(loadMimeTypes);
-
async function getMimeTypes() {
if (mimeTypes === null) {
- loadMimeTypes(await options.waitForOptions());
+ loadMimeTypes();
}
return mimeTypes;
}
export default {
- getMimeTypes
+ getMimeTypes,
+ loadMimeTypes
}
\ No newline at end of file
diff --git a/src/public/javascripts/services/options.js b/src/public/javascripts/services/options.js
index 67059f1c0..a92b8151e 100644
--- a/src/public/javascripts/services/options.js
+++ b/src/public/javascripts/services/options.js
@@ -1,11 +1,9 @@
import server from "./server.js";
-let optionsReady;
-
const loadListeners = [];
class Options {
- constructor(arr) {
+ load(arr) {
this.arr = arr;
}
@@ -37,45 +35,21 @@ class Options {
is(key) {
return this.arr[key] === 'true';
}
+
+ set(key, value) {
+ this.arr[key] = value;
+ }
+
+ async save(key, value) {
+ this.set(key, value);
+
+ const payload = {};
+ payload[key] = value;
+
+ await server.put(`options`, payload);
+ }
}
-function reloadOptions() {
- optionsReady = new Promise((resolve, reject) => {
- server.get('options').then(optionArr => {
- const options = new Options(optionArr);
+const options = new Options();
- resolve(options);
-
- for (const listener of loadListeners) {
- listener(options);
- }
- });
- });
-
- return optionsReady;
-}
-
-/**
- * just waits for some options without triggering reload
- *
- * @return {Options}
- */
-async function waitForOptions() {
- return await optionsReady;
-}
-
-reloadOptions(); // initial load
-
-function addLoadListener(listener) {
- loadListeners.push(listener);
-
- // useful when listener has been added after the promise resolved, but can cause double emit if not yet
- // that should not be an issue though
- optionsReady.then(listener);
-}
-
-export default {
- addLoadListener,
- reloadOptions,
- waitForOptions
-}
\ No newline at end of file
+export default options;
\ No newline at end of file
diff --git a/src/public/javascripts/services/protected_session_holder.js b/src/public/javascripts/services/protected_session_holder.js
index 1920c88c8..0c180e7fe 100644
--- a/src/public/javascripts/services/protected_session_holder.js
+++ b/src/public/javascripts/services/protected_session_holder.js
@@ -1,23 +1,19 @@
import utils from "./utils.js";
-import optionsService from './options.js';
+import options from './options.js';
const PROTECTED_SESSION_ID_KEY = 'protectedSessionId';
-let lastProtectedSessionOperationDate = null;
-let protectedSessionTimeout = null;
-
-optionsService.addLoadListener(options => setProtectedSessionTimeout(options.getInt('protectedSessionTimeout')));
+let lastProtectedSessionOperationDate = 0;
setInterval(() => {
- if (lastProtectedSessionOperationDate !== null && Date.now() - lastProtectedSessionOperationDate.getTime() > protectedSessionTimeout * 1000) {
+ const protectedSessionTimeout = options.getInt('protectedSessionTimeout');
+ if (lastProtectedSessionOperationDate
+ && Date.now() - lastProtectedSessionOperationDate > protectedSessionTimeout * 1000) {
+
resetProtectedSession();
}
}, 5000);
-function setProtectedSessionTimeout(encSessTimeout) {
- protectedSessionTimeout = encSessTimeout;
-}
-
function setProtectedSessionId(id) {
// using session cookie so that it disappears after browser/tab is closed
utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id);
@@ -37,7 +33,7 @@ function isProtectedSessionAvailable() {
function touchProtectedSession() {
if (isProtectedSessionAvailable()) {
- lastProtectedSessionOperationDate = new Date();
+ lastProtectedSessionOperationDate = Date.now();
setProtectedSessionId(utils.getCookie(PROTECTED_SESSION_ID_KEY));
}
@@ -47,6 +43,5 @@ export default {
setProtectedSessionId,
resetProtectedSession,
isProtectedSessionAvailable,
- setProtectedSessionTimeout,
touchProtectedSession
};
\ No newline at end of file
diff --git a/src/public/javascripts/services/search_notes.js b/src/public/javascripts/services/search_notes.js
index e02a77a77..de67ececa 100644
--- a/src/public/javascripts/services/search_notes.js
+++ b/src/public/javascripts/services/search_notes.js
@@ -1,9 +1,21 @@
-import treeService from './tree.js';
-import treeCache from "./tree_cache.js";
-import server from './server.js';
import toastService from "./toast.js";
import appContext from "./app_context.js";
+const helpText = `
+Search tips - also see
+
+
+ - Just enter any text for full text search
+ @abc
- returns notes with label abc
+ @year=2019
- matches notes with label year
having value 2019
+ @rock @pop
- matches notes which have both rock
and pop
labels
+ @rock or @pop
- only one of the labels must be present
+ @year<=2000
- numerical comparison (also >, >=, <).
+ @dateCreated>=MONTH-1
- notes created in the last month
+ =handler
- will execute script defined in handler
relation to get results
+
+
`;
+
async function refreshSearch() {
const activeNode = appContext.getMainNoteTree().getActiveNode();
@@ -23,10 +35,6 @@ function init() {
}
export default {
- // toggleSearch,
- // resetSearch,
- // showSearch,
- // doSearch,
refreshSearch,
init,
getHelpText: () => helpText
diff --git a/src/public/javascripts/services/spell_check.js b/src/public/javascripts/services/spell_check.js
index aee0f379c..8407d37ec 100644
--- a/src/public/javascripts/services/spell_check.js
+++ b/src/public/javascripts/services/spell_check.js
@@ -1,8 +1,6 @@
-import optionsService from "./options.js";
+import options from "./options.js";
export async function initSpellCheck() {
- const options = await optionsService.waitForOptions();
-
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
const {remote, shell} = require('electron');
diff --git a/src/public/javascripts/services/split.js b/src/public/javascripts/services/split.js
index 5e51809f1..29a5814f4 100644
--- a/src/public/javascripts/services/split.js
+++ b/src/public/javascripts/services/split.js
@@ -1,17 +1,7 @@
-import server from "./server.js";
-import optionService from "./options.js";
+import options from "./options.js";
let instance;
-async function getPaneWidths() {
- const options = await optionService.waitForOptions();
-
- return {
- leftPaneWidth: options.getInt('leftPaneWidth'),
- rightPaneWidth: options.getInt('rightPaneWidth')
- };
-}
-
async function setupSplit(left, right) {
if (instance) {
instance.destroy();
@@ -24,15 +14,16 @@ async function setupSplit(left, right) {
return;
}
- const {leftPaneWidth, rightPaneWidth} = await getPaneWidths();
+ const leftPaneWidth = options.getInt('leftPaneWidth');
+ const rightPaneWidth = options.getInt('rightPaneWidth');
if (left && right) {
instance = Split(['#left-pane', '#center-pane', '#right-pane'], {
sizes: [leftPaneWidth, 100 - leftPaneWidth - rightPaneWidth, rightPaneWidth],
gutterSize: 5,
onDragEnd: sizes => {
- server.put('options/leftPaneWidth/' + Math.round(sizes[0]));
- server.put('options/rightPaneWidth/' + Math.round(sizes[2]));
+ options.save('leftPaneWidth', Math.round(sizes[0]));
+ options.save('rightPaneWidth', Math.round(sizes[2]));
}
});
}
@@ -41,7 +32,7 @@ async function setupSplit(left, right) {
sizes: [leftPaneWidth, 100 - leftPaneWidth],
gutterSize: 5,
onDragEnd: sizes => {
- server.put('options/leftPaneWidth/' + Math.round(sizes[0]));
+ options.save('leftPaneWidth', Math.round(sizes[0]));
}
});
}
@@ -50,7 +41,7 @@ async function setupSplit(left, right) {
sizes: [100 - rightPaneWidth, rightPaneWidth],
gutterSize: 5,
onDragEnd: sizes => {
- server.put('options/rightPaneWidth/' + Math.round(sizes[1]));
+ options.save('rightPaneWidth', Math.round(sizes[1]));
}
});
}
diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js
index 0c691afe9..5a3709a69 100644
--- a/src/public/javascripts/services/tab_context.js
+++ b/src/public/javascripts/services/tab_context.js
@@ -9,12 +9,6 @@ import Component from "../widgets/component.js";
import treeCache from "./tree_cache.js";
import hoistedNoteService from "./hoisted_note.js";
-let showSidebarInNewTab = true;
-
-optionsService.addLoadListener(options => {
- showSidebarInNewTab = options.is('showSidebarInNewTab');
-});
-
class TabContext extends Component {
/**
* @param {AppContext} appContext
diff --git a/src/public/javascripts/services/tree_cache.js b/src/public/javascripts/services/tree_cache.js
index 7fe0a54ba..e29d1411a 100644
--- a/src/public/javascripts/services/tree_cache.js
+++ b/src/public/javascripts/services/tree_cache.js
@@ -5,6 +5,7 @@ import server from "./server.js";
import {LoadResults} from "./load_results.js";
import NoteComplement from "../entities/note_complement.js";
import appContext from "./app_context.js";
+import options from "./options.js";
/**
* TreeCache keeps a read only cache of note tree structure in frontend's memory.
@@ -351,6 +352,12 @@ class TreeCache {
loadResults.addNoteRevision(sync.entityId, sync.noteId, sync.sourceId);
});
+ syncRows.filter(sync => sync.entityName === 'options').forEach(sync => {
+ options.set(sync.entity.name, sync.entity.value);
+
+ loadResults.addOption(sync.entity.name);
+ });
+
appContext.trigger('entitiesReloaded', {loadResults});
}
}
diff --git a/src/public/javascripts/services/ws.js b/src/public/javascripts/services/ws.js
index d85ba5860..4c74daa55 100644
--- a/src/public/javascripts/services/ws.js
+++ b/src/public/javascripts/services/ws.js
@@ -130,7 +130,7 @@ async function consumeSyncData() {
await treeCache.processSyncRows(allSyncData);
}
catch (e) {
- logError(`Encountered error ${e.message}, reloading frontend.`);
+ logError(`Encountered error ${e.message}: ${e.stack}, reloading frontend.`);
// if there's an error in updating the frontend then the easy option to recover is to reload the frontend completely
utils.reloadApp();
diff --git a/src/public/javascripts/services/zoom.js b/src/public/javascripts/services/zoom.js
index a47837295..781189f01 100644
--- a/src/public/javascripts/services/zoom.js
+++ b/src/public/javascripts/services/zoom.js
@@ -1,51 +1,47 @@
-import server from "./server.js";
-import utils from "./utils.js";
-import optionsService from "./options.js";
+import options from "./options.js";
+import Component from "../widgets/component.js";
const MIN_ZOOM = 0.5;
const MAX_ZOOM = 2.0;
-async function decreaseZoomFactor() {
- await setZoomFactorAndSave(getCurrentZoom() - 0.1);
-}
+export default class ZoomService extends Component {
+ constructor(appContext) {
+ super(appContext);
-async function increaseZoomFactor() {
- await setZoomFactorAndSave(getCurrentZoom() + 0.1);
-}
-
-function setZoomFactor(zoomFactor) {
- zoomFactor = parseFloat(zoomFactor);
-
- const webFrame = require('electron').webFrame;
- webFrame.setZoomFactor(zoomFactor);
-}
-
-async function setZoomFactorAndSave(zoomFactor) {
- if (!utils.isElectron()) {
- return;
+ this.setZoomFactor(options.getFloat('zoomFactor'));
}
- if (zoomFactor >= MIN_ZOOM && zoomFactor <= MAX_ZOOM) {
- setZoomFactor(zoomFactor);
-
- await server.put('options/zoomFactor/' + zoomFactor);
+ setZoomFactor(zoomFactor) {
+ zoomFactor = parseFloat(zoomFactor);
+
+ const webFrame = require('electron').webFrame;
+ webFrame.setZoomFactor(zoomFactor);
}
- else {
- console.log(`Zoom factor ${zoomFactor} outside of the range, ignored.`);
+
+ async setZoomFactorAndSave(zoomFactor) {
+ if (zoomFactor >= MIN_ZOOM && zoomFactor <= MAX_ZOOM) {
+ this.setZoomFactor(zoomFactor);
+
+ await options.save('zoomFactor', zoomFactor);
+ }
+ else {
+ console.log(`Zoom factor ${zoomFactor} outside of the range, ignored.`);
+ }
+ }
+
+ getCurrentZoom() {
+ return require('electron').webFrame.getZoomFactor();
}
-}
-function getCurrentZoom() {
- return require('electron').webFrame.getZoomFactor();
-}
+ zoomOutListener() {
+ this.setZoomFactorAndSave(this.getCurrentZoom() - 0.1);
+ }
-if (utils.isElectron()) {
- optionsService.addLoadListener(options => setZoomFactor(options.getFloat('zoomFactor')))
-}
+ zoomInListener() {
+ this.setZoomFactorAndSave(this.getCurrentZoom() + 0.1);
+ }
-export default {
- decreaseZoomFactor,
- increaseZoomFactor,
- setZoomFactor,
- setZoomFactorAndSave
+ setZoomFactorAndSaveListener({zoomFactor}) {
+ this.setZoomFactorAndSave(zoomFactor);
+ }
}
\ No newline at end of file
diff --git a/src/public/javascripts/widgets/note_tree.js b/src/public/javascripts/widgets/note_tree.js
index 275b7952f..567eff5f6 100644
--- a/src/public/javascripts/widgets/note_tree.js
+++ b/src/public/javascripts/widgets/note_tree.js
@@ -118,7 +118,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
autoExpandMS: 600,
dragStart: (node, data) => {
// don't allow dragging root node
- if (node.data.noteId === hoistedNoteService.getHoistedNoteNoPromise()
+ if (node.data.noteId === hoistedNoteService.getHoistedNoteId()
|| node.getParent().data.noteType === 'search') {
return false;
}
@@ -141,7 +141,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
dragDrop: async (node, data) => {
if ((data.hitMode === 'over' && node.data.noteType === 'search') ||
(['after', 'before'].includes(data.hitMode)
- && (node.data.noteId === hoistedNoteService.getHoistedNoteNoPromise() || node.getParent().data.noteType === 'search'))) {
+ && (node.data.noteId === hoistedNoteService.getHoistedNoteId() || node.getParent().data.noteType === 'search'))) {
const infoDialog = await import('../dialogs/info.js');
diff --git a/src/public/javascripts/widgets/search_box.js b/src/public/javascripts/widgets/search_box.js
index 55c9ba8a7..432601411 100644
--- a/src/public/javascripts/widgets/search_box.js
+++ b/src/public/javascripts/widgets/search_box.js
@@ -1,25 +1,10 @@
import BasicWidget from "./basic_widget.js";
-import treeService from "../services/tree.js";
+import searchService from "../services/search_notes.js";
import treeCache from "../services/tree_cache.js";
import toastService from "../services/toast.js";
import appContext from "../services/app_context.js";
import noteCreateService from "../services/note_create.js";
-const helpText = `
-Search tips - also see
-
-
- - Just enter any text for full text search
- @abc
- returns notes with label abc
- @year=2019
- matches notes with label year
having value 2019
- @rock @pop
- matches notes which have both rock
and pop
labels
- @rock or @pop
- only one of the labels must be present
- @year<=2000
- numerical comparison (also >, >=, <).
- @dateCreated>=MONTH-1
- notes created in the last month
- =handler
- will execute script defined in handler
relation to get results
-
-`;
-
const TPL = `
+
+
+
+
+
+
+
+`;
+
+export default class SidebarToggle extends BasicWidget {
+ constructor(appContext) {
+ super(appContext);
+
+ this.paneVisible = {};
+ }
+
+ doRender() {
+ this.$widget = $(TPL);
+
+ this.toggleSidebar('left', options.is('leftPaneVisible'));
+ this.toggleSidebar('right', options.is('rightPaneVisible'));
+
+ $("#show-right-pane-button").on('click', () => toggleAndSave('right', true));
+ $("#hide-right-pane-button").on('click', () => toggleAndSave('right', false));
+
+ $("#show-left-pane-button").on('click', () => toggleAndSave('left', true));
+ $("#hide-left-pane-button").on('click', () => toggleAndSave('left', false));
+
+ splitService.setupSplit(this.paneVisible.left, this.paneVisible.right);
+
+ return this.$widget;
+ }
+
+ toggleSidebar(side, show) {
+ $(`#${side}-pane`).toggle(show);
+ $(`#show-${side}-pane-button`).toggle(!show);
+ $(`#hide-${side}-pane-button`).toggle(show);
+
+ this.paneVisible[side] = show;
+ }
+
+ async toggleAndSave(side, show) {
+ this.toggleSidebar(side, show);
+
+ await options.save(`${side}PaneVisible`, show.toString());
+
+ splitService.setupSplit(this.paneVisible.left, this.paneVisible.right);
+
+ this.trigger('sidebarVisibilityChanged', {side, show});
+ }
+}
diff --git a/src/public/javascripts/widgets/title_bar_buttons.js b/src/public/javascripts/widgets/title_bar_buttons.js
index a958a2002..2addedab0 100644
--- a/src/public/javascripts/widgets/title_bar_buttons.js
+++ b/src/public/javascripts/widgets/title_bar_buttons.js
@@ -1,5 +1,5 @@
import BasicWidget from "./basic_widget.js";
-import optionService from "../services/options.js";
+import options from "../services/options.js";
import utils from "../services/utils.js";
const TPL = `
@@ -23,41 +23,41 @@ export default class TitleBarButtonsWidget extends BasicWidget {
return;
}
- this.$widget = $(TPL);
+ if (!options.is('nativeTitleBarVisible')) {
+ this.$widget = $(TPL);
+ this.$widget.show();
- optionService.waitForOptions().then(options => {
- if (!options.is('nativeTitleBarVisible')) {
- this.$widget.show();
+ const $minimizeBtn = this.$widget.find(".minimize-btn");
+ const $maximizeBtn = this.$widget.find(".maximize-btn");
+ const $closeBtn = this.$widget.find(".close-btn");
- const $minimizeBtn = this.$widget.find(".minimize-btn");
- const $maximizeBtn = this.$widget.find(".maximize-btn");
- const $closeBtn = this.$widget.find(".close-btn");
+ $minimizeBtn.on('click', () => {
+ $minimizeBtn.trigger('blur');
+ const {remote} = require('electron');
+ remote.BrowserWindow.getFocusedWindow().minimize();
+ });
- $minimizeBtn.on('click', () => {
- $minimizeBtn.trigger('blur');
- const {remote} = require('electron');
- remote.BrowserWindow.getFocusedWindow().minimize();
- });
+ $maximizeBtn.on('click', () => {
+ $maximizeBtn.trigger('blur');
+ const {remote} = require('electron');
+ const focusedWindow = remote.BrowserWindow.getFocusedWindow();
- $maximizeBtn.on('click', () => {
- $maximizeBtn.trigger('blur');
- const {remote} = require('electron');
- const focusedWindow = remote.BrowserWindow.getFocusedWindow();
+ if (focusedWindow.isMaximized()) {
+ focusedWindow.unmaximize();
+ } else {
+ focusedWindow.maximize();
+ }
+ });
- if (focusedWindow.isMaximized()) {
- focusedWindow.unmaximize();
- } else {
- focusedWindow.maximize();
- }
- });
-
- $closeBtn.on('click', () => {
- $closeBtn.trigger('blur');
- const {remote} = require('electron');
- remote.BrowserWindow.getFocusedWindow().close();
- });
- }
- });
+ $closeBtn.on('click', () => {
+ $closeBtn.trigger('blur');
+ const {remote} = require('electron');
+ remote.BrowserWindow.getFocusedWindow().close();
+ });
+ }
+ else {
+ this.$widget = $('');
+ }
return this.$widget;
}
diff --git a/src/public/stylesheets/desktop.css b/src/public/stylesheets/desktop.css
index b312cd648..8fc5eede3 100644
--- a/src/public/stylesheets/desktop.css
+++ b/src/public/stylesheets/desktop.css
@@ -146,20 +146,6 @@ body {
border-color: var(--button-border-color);
}
-#hide-right-pane-button, #show-right-pane-button {
- position: fixed;
- bottom: 10px;
- right: 10px;
- z-index: 1000;
-}
-
-#hide-left-pane-button, #show-left-pane-button {
- position: fixed;
- bottom: 10px;
- left: 10px;
- z-index: 1000;
-}
-
#right-pane {
overflow: auto;
padding-top: 4px;
diff --git a/src/services/repository.js b/src/services/repository.js
index 38d835f35..c36cb7782 100644
--- a/src/services/repository.js
+++ b/src/services/repository.js
@@ -110,9 +110,7 @@ async function updateEntity(entity) {
const primaryKey = entity[primaryKeyName];
if (entity.isChanged) {
- if (entityName !== 'options' || entity.isSynced) {
- await syncTableService.addEntitySync(entityName, primaryKey);
- }
+ await syncTableService.addEntitySync(entityName, primaryKey);
if (!cls.isEntityEventsDisabled()) {
const eventPayload = {
diff --git a/src/services/sync.js b/src/services/sync.js
index 8cb12339c..bc6b259fa 100644
--- a/src/services/sync.js
+++ b/src/services/sync.js
@@ -315,10 +315,13 @@ async function getSyncRecords(syncs) {
let length = 0;
for (const sync of syncs) {
- const record = {
- sync: sync,
- entity: await getEntityRow(sync.entityName, sync.entityId)
- };
+ const entity = await getEntityRow(sync.entityName, sync.entityId);
+
+ if (sync.entityName === 'options' && !entity.isSynced) {
+ continue;
+ }
+
+ const record = { sync, entity };
records.push(record);
diff --git a/src/services/ws.js b/src/services/ws.js
index 58bf3ffa0..c0b838ac4 100644
--- a/src/services/ws.js
+++ b/src/services/ws.js
@@ -92,6 +92,9 @@ async function fillInAdditionalProperties(sync) {
} else if (sync.entityName === 'note_reordering') {
sync.positions = await sql.getMap(`SELECT branchId, notePosition FROM branches WHERE isDeleted = 0 AND parentNoteId = ?`, [sync.entityId]);
}
+ else if (sync.entityName === 'options') {
+ sync.entity = await sql.getRow(`SELECT * FROM options WHERE name = ?`, [sync.entityId]);
+ }
}
async function sendPing(client) {
diff --git a/src/views/desktop.ejs b/src/views/desktop.ejs
index a8af7c11a..b9f415ecd 100644
--- a/src/views/desktop.ejs
+++ b/src/views/desktop.ejs
@@ -14,13 +14,7 @@