options dialog refactoring into more standard widget structure

This commit is contained in:
zadam 2022-11-20 18:29:15 +01:00
parent 02d908df1e
commit a3783b0113
16 changed files with 226 additions and 195 deletions

View File

@ -81,6 +81,18 @@ import MermaidExportButton from "../widgets/floating_buttons/mermaid_export_butt
import EditableCodeButtonsWidget from "../widgets/type_widgets/editable_code_buttons.js"; import EditableCodeButtonsWidget from "../widgets/type_widgets/editable_code_buttons.js";
import ApiLogWidget from "../widgets/api_log.js"; import ApiLogWidget from "../widgets/api_log.js";
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js"; import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
import AppearanceOptions from "../widgets/dialogs/options/appearance.js";
import KeyboardShortcutsOptions from "../widgets/dialogs/options/shortcuts.js";
import TextNotesOptions from "../widgets/dialogs/options/text_notes.js";
import CodeNotesOptions from "../widgets/dialogs/options/code_notes.js";
import ImageOptions from "../widgets/dialogs/options/images.js";
import SpellcheckOptions from "../widgets/dialogs/options/spellcheck.js";
import PasswordOptions from "../widgets/dialogs/options/password.js";
import EtapiOptions from "../widgets/dialogs/options/etapi.js";
import BackupOptions from "../widgets/dialogs/options/backup.js";
import SyncOptions from "../widgets/dialogs/options/sync.js";
import OtherOptions from "../widgets/dialogs/options/other.js";
import AdvancedOptions from "../widgets/dialogs/options/advanced.js";
export default class DesktopLayout { export default class DesktopLayout {
constructor(customWidgets) { constructor(customWidgets) {
@ -241,6 +253,19 @@ export default class DesktopLayout {
.child(new InfoDialog()) .child(new InfoDialog())
.child(new ConfirmDialog()) .child(new ConfirmDialog())
.child(new PromptDialog()) .child(new PromptDialog())
.child(new OptionsDialog()); .child(new OptionsDialog()
.child(new AppearanceOptions())
.child(new KeyboardShortcutsOptions())
.child(new TextNotesOptions())
.child(new CodeNotesOptions())
.child(new ImageOptions())
.child(new SpellcheckOptions())
.child(new PasswordOptions())
.child(new EtapiOptions())
.child(new BackupOptions())
.child(new SyncOptions())
.child(new OtherOptions())
.child(new AdvancedOptions())
);
} }
} }

View File

@ -27,59 +27,9 @@ const TPL = `
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div style="display: flex"> <div style="display: flex">
<ul class="nav nav-tabs flex-column"> <ul class="nav nav-tabs flex-column"></ul>
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#options-appearance">Appearance</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-shortcuts">Shortcuts</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-text-notes">Text notes</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-code-notes">Code notes</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-images">Images</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-spellcheck">Spellcheck</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-password">Password</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-etapi">ETAPI</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-backup">Backup</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-sync-setup">Sync</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-other">Other</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-advanced">Advanced</a>
</li>
</ul>
<br/> <br/>
<div class="tab-content"> <div class="tab-content"></div>
<div id="options-appearance" class="tab-pane active"></div>
<div id="options-shortcuts" class="tab-pane"></div>
<div id="options-text-notes" class="tab-pane"></div>
<div id="options-code-notes" class="tab-pane"></div>
<div id="options-images" class="tab-pane"></div>
<div id="options-spellcheck" class="tab-pane"></div>
<div id="options-password" class="tab-pane"></div>
<div id="options-etapi" class="tab-pane"></div>
<div id="options-backup" class="tab-pane"></div>
<div id="options-sync-setup" class="tab-pane"></div>
<div id="options-other" class="tab-pane"></div>
<div id="options-advanced" class="tab-pane"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -90,36 +40,51 @@ const TPL = `
export default class OptionsDialog extends BasicWidget { export default class OptionsDialog extends BasicWidget {
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$navTabs = this.$widget.find(".nav-tabs");
this.$tabContent = this.$widget.find(".tab-content");
for (const child of this.children) {
this.$navTabs.append(
$('<li class="nav-item">')
.append(
$('<a class="nav-link" data-toggle="tab">')
.attr("href", '#options-' + child.constructor.name)
.text(child.tabTitle)
)
);
this.$tabContent.append(
$('<div class="tab-pane">')
.attr("id", "options-" + child.constructor.name)
);
}
} }
async showOptionsEvent({openTab}) { async showOptionsEvent({openTab}) {
const options = await server.get('options'); const optionPromise = server.get('options');
utils.openDialog(this.$widget); for (const child of this.children) {
child.lazyRender();
(await Promise.all([ this.$widget.find("#options-" + child.constructor.name)
import('./options/appearance.js'), .empty()
import('./options/shortcuts.js'), .append(child.$widget);
import('./options/text_notes.js'),
import('./options/code_notes.js'),
import('./options/images.js'),
import('./options/spellcheck.js'),
import('./options/password.js'),
import('./options/etapi.js'),
import('./options/backup.js'),
import('./options/sync.js'),
import('./options/other.js'),
import('./options/advanced.js')
]))
.map(m => new m.default)
.forEach(tab => {
if (tab.optionsLoaded) {
tab.optionsLoaded(options)
} }
});
if (openTab) { const options = await optionPromise;
$(`.nav-link[href='#options-${openTab}']`).trigger("click");
for (const child of this.children) {
if (child.optionsLoaded) {
child.optionsLoaded(options)
} }
} }
await utils.openDialog(this.$widget);
if (!openTab) {
openTab = "AppearanceOptions";
}
this.$widget.find(`.nav-link[href='#options-${openTab}']`).trigger("click");
}
} }

View File

@ -1,5 +1,6 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<h4 style="margin-top: 0;">Sync</h4> <h4 style="margin-top: 0;">Sync</h4>
@ -46,17 +47,19 @@ const TPL = `
<button id="vacuum-database-button" class="btn">Vacuum database</button>`; <button id="vacuum-database-button" class="btn">Vacuum database</button>`;
export default class AdvancedOptions { export default class AdvancedOptions extends OptionsTab {
constructor() { get tabTitle() { return "Advanced" }
$("#options-advanced").html(TPL);
this.$forceFullSyncButton = $("#force-full-sync-button"); lazyRender() {
this.$fillEntityChangesButton = $("#fill-entity-changes-button"); this.$widget = $(TPL);
this.$anonymizeFullButton = $("#anonymize-full-button");
this.$anonymizeLightButton = $("#anonymize-light-button"); this.$forceFullSyncButton = this.$widget.find("#force-full-sync-button");
this.$vacuumDatabaseButton = $("#vacuum-database-button"); this.$fillEntityChangesButton = this.$widget.find("#fill-entity-changes-button");
this.$findAndFixConsistencyIssuesButton = $("#find-and-fix-consistency-issues-button"); this.$anonymizeFullButton = this.$widget.find("#anonymize-full-button");
this.$checkIntegrityButton = $("#check-integrity-button"); this.$anonymizeLightButton = this.$widget.find("#anonymize-light-button");
this.$vacuumDatabaseButton = this.$widget.find("#vacuum-database-button");
this.$findAndFixConsistencyIssuesButton = this.$widget.find("#find-and-fix-consistency-issues-button");
this.$checkIntegrityButton = this.$widget.find("#check-integrity-button");
this.$forceFullSyncButton.on('click', async () => { this.$forceFullSyncButton.on('click', async () => {
await server.post('sync/force-full-sync'); await server.post('sync/force-full-sync');

View File

@ -1,6 +1,7 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import utils from "../../../services/utils.js"; import utils from "../../../services/utils.js";
import appContext from "../../../services/app_context.js"; import appContext from "../../../services/app_context.js";
import OptionsTab from "./options_tab.js";
const FONT_FAMILIES = [ const FONT_FAMILIES = [
{ value: "theme", label: "Theme defined" }, { value: "theme", label: "Theme defined" },
@ -174,33 +175,35 @@ const TPL = `
</p> </p>
</form>`; </form>`;
export default class ApperanceOptions { export default class AppearanceOptions extends OptionsTab {
constructor() { get tabTitle() { return "Appearance" }
$("#options-appearance").html(TPL);
this.$zoomFactorSelect = $("#zoom-factor-select"); lazyRender() {
this.$nativeTitleBarSelect = $("#native-title-bar-select"); this.$widget = $(TPL);
this.$themeSelect = $("#theme-select"); this.$zoomFactorSelect = this.$widget.find("#zoom-factor-select");
this.$overrideThemeFonts = $("#override-theme-fonts"); this.$nativeTitleBarSelect = this.$widget.find("#native-title-bar-select");
this.$overridenFontSettings = $("#overriden-font-settings"); this.$themeSelect = this.$widget.find("#theme-select");
this.$overrideThemeFonts = this.$widget.find("#override-theme-fonts");
this.$mainFontSize = $("#main-font-size"); this.$overridenFontSettings = this.$widget.find("#overriden-font-settings");
this.$mainFontFamily = $("#main-font-family");
this.$treeFontSize = $("#tree-font-size"); this.$mainFontSize = this.$widget.find("#main-font-size");
this.$treeFontFamily = $("#tree-font-family"); this.$mainFontFamily = this.$widget.find("#main-font-family");
this.$detailFontSize = $("#detail-font-size"); this.$treeFontSize = this.$widget.find("#tree-font-size");
this.$detailFontFamily = $("#detail-font-family"); this.$treeFontFamily = this.$widget.find("#tree-font-family");
this.$monospaceFontSize = $("#monospace-font-size"); this.$detailFontSize = this.$widget.find("#detail-font-size");
this.$monospaceFontFamily = $("#monospace-font-family"); this.$detailFontFamily = this.$widget.find("#detail-font-family");
$(".reload-frontend-button").on("click", () => utils.reloadFrontendApp("changes from appearance options")); this.$monospaceFontSize = this.$widget.find("#monospace-font-size");
this.$monospaceFontFamily = this.$widget.find("#monospace-font-family");
this.$body = $("body"); this.$widget.find(".reload-frontend-button").on("click", () => utils.reloadFrontendApp("changes from appearance options"));
this.$body = this.$widget.find("body");
this.$themeSelect.on('change', async () => { this.$themeSelect.on('change', async () => {
const newTheme = this.$themeSelect.val(); const newTheme = this.$themeSelect.val();
@ -237,7 +240,7 @@ export default class ApperanceOptions {
this['$' + optionName].on('change', () => server.put(`options/${optionName}/${this['$' + optionName].val()}`)); this['$' + optionName].on('change', () => server.put(`options/${optionName}/${this['$' + optionName].val()}`));
} }
this.$maxContentWidth = $("#max-content-width"); this.$maxContentWidth = this.$widget.find("#max-content-width");
this.$maxContentWidth.on('change', async () => { this.$maxContentWidth.on('change', async () => {
const maxContentWidth = this.$maxContentWidth.val(); const maxContentWidth = this.$maxContentWidth.val();

View File

@ -1,5 +1,6 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<h4>Automatic backup</h4> <h4>Automatic backup</h4>
@ -32,11 +33,13 @@ const TPL = `
<button id="backup-database-button" class="btn">Backup database now</button><br/><br/> <button id="backup-database-button" class="btn">Backup database now</button><br/><br/>
`; `;
export default class BackupOptions { export default class BackupOptions extends OptionsTab {
constructor() { get tabTitle() { return "Backup" }
$("#options-backup").html(TPL);
this.$backupDatabaseButton = $("#backup-database-button"); lazyRender() {
this.$widget = $(TPL);
this.$backupDatabaseButton = this.$widget.find("#backup-database-button");
this.$backupDatabaseButton.on('click', async () => { this.$backupDatabaseButton.on('click', async () => {
const {backupFile} = await server.post('database/backup-database'); const {backupFile} = await server.post('database/backup-database');
@ -44,9 +47,9 @@ export default class BackupOptions {
toastService.showMessage("Database has been backed up to " + backupFile, 10000); toastService.showMessage("Database has been backed up to " + backupFile, 10000);
}); });
this.$dailyBackupEnabled = $("#daily-backup-enabled"); this.$dailyBackupEnabled = this.$widget.find("#daily-backup-enabled");
this.$weeklyBackupEnabled = $("#weekly-backup-enabled"); this.$weeklyBackupEnabled = this.$widget.find("#weekly-backup-enabled");
this.$monthlyBackupEnabled = $("#monthly-backup-enabled"); this.$monthlyBackupEnabled = this.$widget.find("#monthly-backup-enabled");
this.$dailyBackupEnabled.on('change', () => { this.$dailyBackupEnabled.on('change', () => {
const opts = { 'dailyBackupEnabled': this.$dailyBackupEnabled.is(":checked") ? "true" : "false" }; const opts = { 'dailyBackupEnabled': this.$dailyBackupEnabled.is(":checked") ? "true" : "false" };

View File

@ -2,6 +2,7 @@ import mimeTypesService from "../../../services/mime_types.js";
import options from "../../../services/options.js"; import options from "../../../services/options.js";
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<div> <div>
@ -39,26 +40,28 @@ const TPL = `
<ul id="options-mime-types" style="max-height: 500px; overflow: auto; list-style-type: none;"></ul> <ul id="options-mime-types" style="max-height: 500px; overflow: auto; list-style-type: none;"></ul>
</div>`; </div>`;
export default class CodeNotesOptions { export default class CodeNotesOptions extends OptionsTab {
constructor() { get tabTitle() { return "Code notes" }
$("#options-code-notes").html(TPL);
this.$vimKeymapEnabled = $("#vim-keymap-enabled"); lazyRender() {
this.$widget = $(TPL);
this.$vimKeymapEnabled = this.$widget.find("#vim-keymap-enabled");
this.$vimKeymapEnabled.on('change', () => { this.$vimKeymapEnabled.on('change', () => {
const opts = { 'vimKeymapEnabled': this.$vimKeymapEnabled.is(":checked") ? "true" : "false" }; const opts = { 'vimKeymapEnabled': this.$vimKeymapEnabled.is(":checked") ? "true" : "false" };
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved.")); server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
return false; return false;
}); });
this.$codeLineWrapEnabled = $("#line-wrap-enabled"); this.$codeLineWrapEnabled = this.$widget.find("#line-wrap-enabled");
this.$codeLineWrapEnabled.on('change', () => { this.$codeLineWrapEnabled.on('change', () => {
const opts = { 'codeLineWrapEnabled': this.$codeLineWrapEnabled.is(":checked") ? "true" : "false" }; const opts = { 'codeLineWrapEnabled': this.$codeLineWrapEnabled.is(":checked") ? "true" : "false" };
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved.")); server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
return false; return false;
}); });
this.$mimeTypes = $("#options-mime-types"); this.$mimeTypes = this.$widget.find("#options-mime-types");
this.$autoReadonlySizeCode = $("#auto-readonly-size-code"); this.$autoReadonlySizeCode = this.$widget.find("#auto-readonly-size-code");
this.$autoReadonlySizeCode.on('change', () => { this.$autoReadonlySizeCode.on('change', () => {
const opts = { 'autoReadonlySizeCode': this.$autoReadonlySizeCode.val() }; const opts = { 'autoReadonlySizeCode': this.$autoReadonlySizeCode.val() };
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved.")); server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
@ -96,7 +99,7 @@ export default class CodeNotesOptions {
const enabledMimeTypes = []; const enabledMimeTypes = [];
this.$mimeTypes.find("input:checked").each( this.$mimeTypes.find("input:checked").each(
(i, el) => enabledMimeTypes.push($(el).attr("data-mime-type"))); (i, el) => enabledMimeTypes.push(this.$widget.find(el).attr("data-mime-type")));
await options.save('codeNotesMimeTypes', JSON.stringify(enabledMimeTypes)); await options.save('codeNotesMimeTypes', JSON.stringify(enabledMimeTypes));

View File

@ -1,6 +1,7 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import dialogService from "../../dialog.js"; import dialogService from "../../dialog.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<h4>ETAPI</h4> <h4>ETAPI</h4>
@ -45,11 +46,13 @@ const TPL = `
} }
</style>`; </style>`;
export default class EtapiOptions { export default class EtapiOptions extends OptionsTab {
constructor() { get tabTitle() { return "ETAPI" }
$("#options-etapi").html(TPL);
$("#create-etapi-token").on("click", async () => { lazyRender() {
this.$widget = $(TPL);
this.$widget.find("#create-etapi-token").on("click", async () => {
const tokenName = await dialogService.prompt({ const tokenName = await dialogService.prompt({
title: "New ETAPI token", title: "New ETAPI token",
message: "Please enter new token's name", message: "Please enter new token's name",
@ -76,8 +79,8 @@ export default class EtapiOptions {
} }
async refreshTokens() { async refreshTokens() {
const $noTokensYet = $("#no-tokens-yet"); const $noTokensYet = this.$widget.find("#no-tokens-yet");
const $tokensTable = $("#tokens-table"); const $tokensTable = this.$widget.find("#tokens-table");
const tokens = await server.get('etapi-tokens'); const tokens = await server.get('etapi-tokens');

View File

@ -1,5 +1,6 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<div> <div>
@ -30,12 +31,14 @@ const TPL = `
</div> </div>
`; `;
export default class ImageOptions { export default class ImageOptions extends OptionsTab {
constructor() { get tabTitle() { return "Images" }
$("#options-images").html(TPL);
this.$imageMaxWidthHeight = $("#image-max-width-height"); lazyRender() {
this.$imageJpegQuality = $("#image-jpeg-quality"); this.$widget = $(TPL);
this.$imageMaxWidthHeight = this.$widget.find("#image-max-width-height");
this.$imageJpegQuality = this.$widget.find("#image-jpeg-quality");
this.$imageMaxWidthHeight.on('change', () => { this.$imageMaxWidthHeight.on('change', () => {
const opts = { 'imageMaxWidthHeight': this.$imageMaxWidthHeight.val() }; const opts = { 'imageMaxWidthHeight': this.$imageMaxWidthHeight.val() };
@ -51,7 +54,7 @@ export default class ImageOptions {
return false; return false;
}); });
this.$downloadImagesAutomatically = $("#download-images-automatically"); this.$downloadImagesAutomatically = this.$widget.find("#download-images-automatically");
this.$downloadImagesAutomatically.on("change", () => { this.$downloadImagesAutomatically.on("change", () => {
const isChecked = this.$downloadImagesAutomatically.prop("checked"); const isChecked = this.$downloadImagesAutomatically.prop("checked");
@ -60,8 +63,8 @@ export default class ImageOptions {
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved.")); server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
}); });
this.$enableImageCompression = $("#image-compresion-enabled"); this.$enableImageCompression = this.$widget.find("#image-compresion-enabled");
this.$imageCompressionWrapper = $("#image-compression-enabled-wraper"); this.$imageCompressionWrapper = this.$widget.find("#image-compression-enabled-wraper");
this.setImageCompression = (isChecked) => { this.setImageCompression = (isChecked) => {
if (isChecked) { if (isChecked) {

View File

@ -0,0 +1,5 @@
import BasicWidget from "../../basic_widget.js";
export default class OptionsTab extends BasicWidget {
}

View File

@ -1,5 +1,6 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<div> <div>
@ -52,11 +53,13 @@ const TPL = `
</div> </div>
</div>`; </div>`;
export default class OtherOptions { export default class OtherOptions extends OptionsTab {
constructor() { get tabTitle() { return "Other" }
$("#options-other").html(TPL);
this.$trayEnabled = $("#tray-enabled"); lazyRender() {
this.$widget = $(TPL);
this.$trayEnabled = this.$widget.find("#tray-enabled");
this.$trayEnabled.on('change', () => { this.$trayEnabled.on('change', () => {
const opts = { 'disableTray': !this.$trayEnabled.is(":checked") ? "true" : "false" }; const opts = { 'disableTray': !this.$trayEnabled.is(":checked") ? "true" : "false" };
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved.")); server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
@ -64,7 +67,7 @@ export default class OtherOptions {
return false; return false;
}); });
this.$eraseEntitiesAfterTimeInSeconds = $("#erase-entities-after-time-in-seconds"); this.$eraseEntitiesAfterTimeInSeconds = this.$widget.find("#erase-entities-after-time-in-seconds");
this.$eraseEntitiesAfterTimeInSeconds.on('change', () => { this.$eraseEntitiesAfterTimeInSeconds.on('change', () => {
const eraseEntitiesAfterTimeInSeconds = this.$eraseEntitiesAfterTimeInSeconds.val(); const eraseEntitiesAfterTimeInSeconds = this.$eraseEntitiesAfterTimeInSeconds.val();
@ -76,14 +79,14 @@ export default class OtherOptions {
return false; return false;
}); });
this.$eraseDeletedNotesButton = $("#erase-deleted-notes-now-button"); this.$eraseDeletedNotesButton = this.$widget.find("#erase-deleted-notes-now-button");
this.$eraseDeletedNotesButton.on('click', () => { this.$eraseDeletedNotesButton.on('click', () => {
server.post('notes/erase-deleted-notes-now').then(() => { server.post('notes/erase-deleted-notes-now').then(() => {
toastService.showMessage("Deleted notes have been erased."); toastService.showMessage("Deleted notes have been erased.");
}); });
}); });
this.$noteRevisionsTimeInterval = $("#note-revision-snapshot-time-interval-in-seconds"); this.$noteRevisionsTimeInterval = this.$widget.find("#note-revision-snapshot-time-interval-in-seconds");
this.$noteRevisionsTimeInterval.on('change', () => { this.$noteRevisionsTimeInterval.on('change', () => {
const opts = { 'noteRevisionSnapshotTimeInterval': this.$noteRevisionsTimeInterval.val() }; const opts = { 'noteRevisionSnapshotTimeInterval': this.$noteRevisionsTimeInterval.val() };
@ -92,7 +95,7 @@ export default class OtherOptions {
return false; return false;
}); });
this.$checkForUpdates = $("#check-for-updates"); this.$checkForUpdates = this.$widget.find("#check-for-updates");
this.$checkForUpdates.on("change", () => { this.$checkForUpdates.on("change", () => {
const isChecked = this.$checkForUpdates.prop("checked"); const isChecked = this.$checkForUpdates.prop("checked");
const opts = { 'checkForUpdates': isChecked ? 'true' : 'false' }; const opts = { 'checkForUpdates': isChecked ? 'true' : 'false' };

View File

@ -1,6 +1,7 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import protectedSessionHolder from "../../../services/protected_session_holder.js"; import protectedSessionHolder from "../../../services/protected_session_holder.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<div> <div>
@ -46,17 +47,19 @@ const TPL = `
</div> </div>
</div>`; </div>`;
export default class PasswordOptions { export default class PasswordOptions extends OptionsTab {
constructor() { get tabTitle() { return "Password" }
$("#options-password").html(TPL);
this.$passwordHeading = $("#password-heading"); lazyRender() {
this.$changePasswordForm = $("#change-password-form"); this.$widget = $(TPL);
this.$oldPassword = $("#old-password");
this.$newPassword1 = $("#new-password1"); this.$passwordHeading = this.$widget.find("#password-heading");
this.$newPassword2 = $("#new-password2"); this.$changePasswordForm = this.$widget.find("#change-password-form");
this.$savePasswordButton = $("#save-password-button"); this.$oldPassword = this.$widget.find("#old-password");
this.$resetPasswordButton = $("#reset-password-button"); this.$newPassword1 = this.$widget.find("#new-password1");
this.$newPassword2 = this.$widget.find("#new-password2");
this.$savePasswordButton = this.$widget.find("#save-password-button");
this.$resetPasswordButton = this.$widget.find("#reset-password-button");
this.$resetPasswordButton.on("click", async () => { this.$resetPasswordButton.on("click", async () => {
if (confirm("By resetting the password you will forever lose access to all your existing protected notes. Do you really want to reset the password?")) { if (confirm("By resetting the password you will forever lose access to all your existing protected notes. Do you really want to reset the password?")) {
@ -71,7 +74,7 @@ export default class PasswordOptions {
this.$changePasswordForm.on('submit', () => this.save()); this.$changePasswordForm.on('submit', () => this.save());
this.$protectedSessionTimeout = $("#protected-session-timeout-in-seconds"); this.$protectedSessionTimeout = this.$widget.find("#protected-session-timeout-in-seconds");
this.$protectedSessionTimeout.on('change', () => { this.$protectedSessionTimeout.on('change', () => {
const protectedSessionTimeout = this.$protectedSessionTimeout.val(); const protectedSessionTimeout = this.$protectedSessionTimeout.val();
@ -87,7 +90,7 @@ export default class PasswordOptions {
optionsLoaded(options) { optionsLoaded(options) {
const isPasswordSet = options.isPasswordSet === 'true'; const isPasswordSet = options.isPasswordSet === 'true';
$("#old-password-form-group").toggle(isPasswordSet); this.$widget.find("#old-password-form-group").toggle(isPasswordSet);
this.$passwordHeading.text(isPasswordSet ? 'Change password' : 'Set password'); this.$passwordHeading.text(isPasswordSet ? 'Change password' : 'Set password');
this.$savePasswordButton.text(isPasswordSet ? 'Change password' : 'Set password'); this.$savePasswordButton.text(isPasswordSet ? 'Change password' : 'Set password');
this.$protectedSessionTimeout.val(options['protectedSessionTimeout']); this.$protectedSessionTimeout.val(options['protectedSessionTimeout']);

View File

@ -1,6 +1,7 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import utils from "../../../services/utils.js"; import utils from "../../../services/utils.js";
import dialogService from "../../dialog.js"; import dialogService from "../../dialog.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<h4>Keyboard shortcuts</h4> <h4>Keyboard shortcuts</h4>
@ -34,13 +35,15 @@ const TPL = `
let globActions; let globActions;
export default class KeyboardShortcutsOptions { export default class KeyboardShortcutsOptions extends OptionsTab {
constructor() { get tabTitle() { return "Shortcuts" }
$("#options-shortcuts").html(TPL);
$("#options-keyboard-shortcuts-reload-app").on("click", () => utils.reloadFrontendApp()); lazyRender() {
this.$widget = $(TPL);
const $table = $("#keyboard-shortcut-table tbody"); this.$widget.find("#options-keyboard-shortcuts-reload-app").on("click", () => utils.reloadFrontendApp());
const $table = this.$widget.find("#keyboard-shortcut-table tbody");
server.get('keyboard-actions').then(actions => { server.get('keyboard-actions').then(actions => {
globActions = actions; globActions = actions;
@ -73,7 +76,7 @@ export default class KeyboardShortcutsOptions {
}); });
$table.on('change', 'input.form-control', e => { $table.on('change', 'input.form-control', e => {
const $input = $(e.target); const $input = this.$widget.find(e.target);
const actionName = $input.attr('data-keyboard-action-name'); const actionName = $input.attr('data-keyboard-action-name');
const shortcuts = $input.val() const shortcuts = $input.val()
.replace('+,', "+Comma") .replace('+,', "+Comma")
@ -87,48 +90,48 @@ export default class KeyboardShortcutsOptions {
server.put('options', opts); server.put('options', opts);
}); });
$("#options-keyboard-shortcuts-set-all-to-default").on('click', async () => { this.$widget.find("#options-keyboard-shortcuts-set-all-to-default").on('click', async () => {
if (!await dialogService.confirm("Do you really want to reset all keyboard shortcuts to the default?")) { if (!await dialogService.confirm("Do you really want to reset all keyboard shortcuts to the default?")) {
return; return;
} }
$table.find('input.form-control').each(function() { $table.find('input.form-control').each(function() {
const defaultShortcuts = $(this).attr('data-default-keyboard-shortcuts'); const defaultShortcuts = this.$widget.find(this).attr('data-default-keyboard-shortcuts');
if ($(this).val() !== defaultShortcuts) { if (this.$widget.find(this).val() !== defaultShortcuts) {
$(this) this.$widget.find(this)
.val(defaultShortcuts) .val(defaultShortcuts)
.trigger('change'); .trigger('change');
} }
}); });
}); });
const $filter = $("#keyboard-shortcut-filter"); const $filter = this.$widget.find("#keyboard-shortcut-filter");
$filter.on('keyup', () => { $filter.on('keyup', () => {
const filter = $filter.val().trim().toLowerCase(); const filter = $filter.val().trim().toLowerCase();
$table.find("tr").each((i, el) => { $table.find("tr").each((i, el) => {
if (!filter) { if (!filter) {
$(el).show(); this.$widget.find(el).show();
return; return;
} }
const actionName = $(el).find('input').attr('data-keyboard-action-name'); const actionName = this.$widget.find(el).find('input').attr('data-keyboard-action-name');
if (!actionName) { if (!actionName) {
$(el).hide(); this.$widget.find(el).hide();
return; return;
} }
const action = globActions.find(act => act.actionName === actionName); const action = globActions.find(act => act.actionName === actionName);
if (!action) { if (!action) {
$(el).hide(); this.$widget.find(el).hide();
return; return;
} }
$(el).toggle(!!( // !! to avoid toggle overloads with different behavior this.$widget.find(el).toggle(!!( // !! to avoid toggle overloads with different behavior
action.actionName.toLowerCase().includes(filter) action.actionName.toLowerCase().includes(filter)
|| action.defaultShortcuts.some(shortcut => shortcut.toLowerCase().includes(filter)) || action.defaultShortcuts.some(shortcut => shortcut.toLowerCase().includes(filter))
|| action.effectiveShortcuts.some(shortcut => shortcut.toLowerCase().includes(filter)) || action.effectiveShortcuts.some(shortcut => shortcut.toLowerCase().includes(filter))

View File

@ -1,6 +1,7 @@
import utils from "../../../services/utils.js"; import utils from "../../../services/utils.js";
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<style> <style>
@ -32,12 +33,14 @@ const TPL = `
<p><strong>Available language codes: </strong> <span id="available-language-codes"></span></p> <p><strong>Available language codes: </strong> <span id="available-language-codes"></span></p>
</div>`; </div>`;
export default class SpellcheckOptions { export default class SpellcheckOptions extends OptionsTab {
constructor() { get tabTitle() { return "Spellcheck" }
$("#options-spellcheck").html(TPL);
this.$spellCheckEnabled = $("#spell-check-enabled"); lazyRender() {
this.$spellCheckLanguageCode = $("#spell-check-language-code"); this.$widget = $(TPL);
this.$spellCheckEnabled = this.$widget.find("#spell-check-enabled");
this.$spellCheckLanguageCode = this.$widget.find("#spell-check-language-code");
this.$spellCheckEnabled.on('change', () => { this.$spellCheckEnabled.on('change', () => {
const opts = { 'spellCheckEnabled': this.$spellCheckEnabled.is(":checked") ? "true" : "false" }; const opts = { 'spellCheckEnabled': this.$spellCheckEnabled.is(":checked") ? "true" : "false" };
@ -53,7 +56,7 @@ export default class SpellcheckOptions {
return false; return false;
}); });
this.$availableLanguageCodes = $("#available-language-codes"); this.$availableLanguageCodes = this.$widget.find("#available-language-codes");
if (utils.isElectron()) { if (utils.isElectron()) {
const { webContents } = utils.dynamicRequire('@electron/remote').getCurrentWindow(); const { webContents } = utils.dynamicRequire('@electron/remote').getCurrentWindow();

View File

@ -1,5 +1,6 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<h4 style="margin-top: 0px;">Sync configuration</h4> <h4 style="margin-top: 0px;">Sync configuration</h4>
@ -37,15 +38,17 @@ const TPL = `
<button id="test-sync-button" class="btn">Test sync</button>`; <button id="test-sync-button" class="btn">Test sync</button>`;
export default class SyncOptions { export default class SyncOptions extends OptionsTab {
constructor() { get tabTitle() { return "Sync" }
$("#options-sync-setup").html(TPL);
this.$form = $("#sync-setup-form"); lazyRender() {
this.$syncServerHost = $("#sync-server-host"); this.$widget = $(TPL);
this.$syncServerTimeout = $("#sync-server-timeout");
this.$syncProxy = $("#sync-proxy"); this.$form = this.$widget.find("#sync-setup-form");
this.$testSyncButton = $("#test-sync-button"); this.$syncServerHost = this.$widget.find("#sync-server-host");
this.$syncServerTimeout = this.$widget.find("#sync-server-timeout");
this.$syncProxy = this.$widget.find("#sync-proxy");
this.$testSyncButton = this.$widget.find("#test-sync-button");
this.$form.on('submit', () => this.save()); this.$form.on('submit', () => this.save());

View File

@ -1,5 +1,6 @@
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.js"; import toastService from "../../../services/toast.js";
import OptionsTab from "./options_tab.js";
const TPL = ` const TPL = `
<p><strong>Settings on this options tab are saved automatically after each change.</strong></p> <p><strong>Settings on this options tab are saved automatically after each change.</strong></p>
@ -36,13 +37,15 @@ const TPL = `
</div> </div>
</form>`; </form>`;
export default class TextNotesOptions { export default class TextNotesOptions extends OptionsTab {
constructor() { get tabTitle() { return "Text notes" }
$("#options-text-notes").html(TPL);
this.$body = $("body"); lazyRender() {
this.$widget = $(TPL);
this.$headingStyle = $("#heading-style"); this.$body = this.$widget.find("body");
this.$headingStyle = this.$widget.find("#heading-style");
this.$headingStyle.on('change', () => { this.$headingStyle.on('change', () => {
const newHeadingStyle = this.$headingStyle.val(); const newHeadingStyle = this.$headingStyle.val();
@ -51,14 +54,14 @@ export default class TextNotesOptions {
server.put('options/headingStyle/' + newHeadingStyle); server.put('options/headingStyle/' + newHeadingStyle);
}); });
this.$minTocHeadings = $("#min-toc-headings"); this.$minTocHeadings = this.$widget.find("#min-toc-headings");
this.$minTocHeadings.on('change', () => { this.$minTocHeadings.on('change', () => {
const minTocHeadings = this.$minTocHeadings.val(); const minTocHeadings = this.$minTocHeadings.val();
server.put('options/minTocHeadings/' + minTocHeadings); server.put('options/minTocHeadings/' + minTocHeadings);
}); });
this.$autoReadonlySizeText = $("#auto-readonly-size-text"); this.$autoReadonlySizeText = this.$widget.find("#auto-readonly-size-text");
this.$autoReadonlySizeText.on('change', () => { this.$autoReadonlySizeText.on('change', () => {
const opts = { 'autoReadonlySizeText': this.$autoReadonlySizeText.val() }; const opts = { 'autoReadonlySizeText': this.$autoReadonlySizeText.val() };
@ -78,7 +81,7 @@ export default class TextNotesOptions {
this.$body.addClass(prefix + value); this.$body.addClass(prefix + value);
} }
async optionsLoaded(options) { optionsLoaded(options) {
this.$headingStyle.val(options.headingStyle); this.$headingStyle.val(options.headingStyle);
this.$minTocHeadings.val(options.minTocHeadings); this.$minTocHeadings.val(options.minTocHeadings);
this.$autoReadonlySizeText.val(options.autoReadonlySizeText); this.$autoReadonlySizeText.val(options.autoReadonlySizeText);

View File

@ -28,7 +28,7 @@ export default class PasswordNoteSetDialog extends BasicWidget {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$openPasswordOptionsButton = this.$widget.find(".open-password-options-button"); this.$openPasswordOptionsButton = this.$widget.find(".open-password-options-button");
this.$openPasswordOptionsButton.on("click", () => { this.$openPasswordOptionsButton.on("click", () => {
this.triggerCommand("showOptions", { openTab: 'password' }); this.triggerCommand("showOptions", { openTab: 'PasswordOptions' });
}); });
} }