mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	options split into individual classes
This commit is contained in:
		
							
								
								
									
										3
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
								
							@@ -6,5 +6,8 @@
 | 
			
		||||
        <option name="TAB_SIZE" value="2" />
 | 
			
		||||
      </value>
 | 
			
		||||
    </option>
 | 
			
		||||
    <JSCodeStyleSettings version="0">
 | 
			
		||||
      <option name="USE_EXPLICIT_JS_EXTENSION" value="TRUE" />
 | 
			
		||||
    </JSCodeStyleSettings>
 | 
			
		||||
  </code_scheme>
 | 
			
		||||
</component>
 | 
			
		||||
@@ -1,22 +1,10 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
import protectedSessionHolder from '../services/protected_session_holder.js';
 | 
			
		||||
import server from '../services/server.js';
 | 
			
		||||
import infoService from "../services/info.js";
 | 
			
		||||
import zoomService from "../services/zoom.js";
 | 
			
		||||
import utils from "../services/utils.js";
 | 
			
		||||
import cssLoader from "../services/css_loader.js";
 | 
			
		||||
import optionsInit from "../services/options_init.js";
 | 
			
		||||
import libraryLoader from "../services/library_loader.js";
 | 
			
		||||
 | 
			
		||||
const $dialog = $("#options-dialog");
 | 
			
		||||
 | 
			
		||||
const tabHandlers = [];
 | 
			
		||||
 | 
			
		||||
function addTabHandler(handler) {
 | 
			
		||||
    tabHandlers.push(handler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function showDialog() {
 | 
			
		||||
    utils.closeActiveDialog();
 | 
			
		||||
 | 
			
		||||
@@ -26,392 +14,19 @@ export async function showDialog() {
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
 | 
			
		||||
    for (const handler of tabHandlers) {
 | 
			
		||||
        if (handler.optionsLoaded) {
 | 
			
		||||
            handler.optionsLoaded(options);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    (await Promise.all([
 | 
			
		||||
        import('./options/advanced.js'),
 | 
			
		||||
        import('./options/appearance.js'),
 | 
			
		||||
        import('./options/change_password.js'),
 | 
			
		||||
        import('./options/note_revisions.js'),
 | 
			
		||||
        import('./options/protected_session.js'),
 | 
			
		||||
        import('./options/sidebar.js'),
 | 
			
		||||
        import('./options/sync.js'),
 | 
			
		||||
    ]))
 | 
			
		||||
        .map(m => new m.default)
 | 
			
		||||
        .forEach(tab => {
 | 
			
		||||
            if (tab.optionsLoaded) {
 | 
			
		||||
                tab.optionsLoaded(options)
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function saveOptions(options) {
 | 
			
		||||
    await server.put('options', options);
 | 
			
		||||
 | 
			
		||||
    infoService.showMessage("Options change have been saved.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
addTabHandler((function() {
 | 
			
		||||
    const $themeSelect = $("#theme-select");
 | 
			
		||||
    const $zoomFactorSelect = $("#zoom-factor-select");
 | 
			
		||||
    const $oneTabDisplaySelect = $("#one-tab-display-select");
 | 
			
		||||
    const $leftPaneMinWidth = $("#left-pane-min-width");
 | 
			
		||||
    const $leftPaneWidthPercent = $("#left-pane-width-percent");
 | 
			
		||||
    const $mainFontSize = $("#main-font-size");
 | 
			
		||||
    const $treeFontSize = $("#tree-font-size");
 | 
			
		||||
    const $detailFontSize = $("#detail-font-size");
 | 
			
		||||
    const $body = $("body");
 | 
			
		||||
    const $container = $("#container");
 | 
			
		||||
 | 
			
		||||
    async function optionsLoaded(options) {
 | 
			
		||||
        const themes = [
 | 
			
		||||
            { val: 'white', title: 'White' },
 | 
			
		||||
            { val: 'dark', title: 'Dark' },
 | 
			
		||||
            { val: 'black', title: 'Black' }
 | 
			
		||||
        ].concat(await server.get('options/user-themes'));
 | 
			
		||||
 | 
			
		||||
        $themeSelect.empty();
 | 
			
		||||
 | 
			
		||||
        for (const theme of themes) {
 | 
			
		||||
            $themeSelect.append($("<option>")
 | 
			
		||||
                .attr("value", theme.val)
 | 
			
		||||
                .attr("data-note-id", theme.noteId)
 | 
			
		||||
                .html(theme.title));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $themeSelect.val(options.theme);
 | 
			
		||||
 | 
			
		||||
        if (utils.isElectron()) {
 | 
			
		||||
            $zoomFactorSelect.val(options.zoomFactor);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $zoomFactorSelect.prop('disabled', true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $oneTabDisplaySelect.val(options.hideTabRowForOneTab === 'true' ? 'hide' : 'show');
 | 
			
		||||
 | 
			
		||||
        $leftPaneMinWidth.val(options.leftPaneMinWidth);
 | 
			
		||||
        $leftPaneWidthPercent.val(options.leftPaneWidthPercent);
 | 
			
		||||
 | 
			
		||||
        $mainFontSize.val(options.mainFontSize);
 | 
			
		||||
        $treeFontSize.val(options.treeFontSize);
 | 
			
		||||
        $detailFontSize.val(options.detailFontSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $themeSelect.change(function() {
 | 
			
		||||
        const newTheme = $(this).val();
 | 
			
		||||
 | 
			
		||||
        for (const clazz of Array.from($body[0].classList)) { // create copy to safely iterate over while removing classes
 | 
			
		||||
            if (clazz.startsWith("theme-")) {
 | 
			
		||||
                $body.removeClass(clazz);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const noteId = $(this).find(":selected").attr("data-note-id");
 | 
			
		||||
 | 
			
		||||
        if (noteId) {
 | 
			
		||||
            // make sure the CSS is loaded
 | 
			
		||||
            // if the CSS has been loaded and then updated then the changes won't take effect though
 | 
			
		||||
            cssLoader.requireCss(`/api/notes/download/${noteId}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $body.addClass("theme-" + newTheme);
 | 
			
		||||
 | 
			
		||||
        server.put('options/theme/' + newTheme);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $zoomFactorSelect.change(function() { zoomService.setZoomFactorAndSave($(this).val()); });
 | 
			
		||||
 | 
			
		||||
    function resizeLeftPanel() {
 | 
			
		||||
        const leftPanePercent = parseInt($leftPaneWidthPercent.val());
 | 
			
		||||
        const rightPanePercent = 100 - leftPanePercent;
 | 
			
		||||
        const leftPaneMinWidth = $leftPaneMinWidth.val();
 | 
			
		||||
 | 
			
		||||
        $container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $oneTabDisplaySelect.change(function() {
 | 
			
		||||
        const hideTabRowForOneTab = $(this).val() === 'hide' ? 'true' : 'false';
 | 
			
		||||
 | 
			
		||||
        server.put('options/hideTabRowForOneTab/' + hideTabRowForOneTab)
 | 
			
		||||
            .then(optionsInit.loadOptions);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $leftPaneMinWidth.change(async function() {
 | 
			
		||||
        await server.put('options/leftPaneMinWidth/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        resizeLeftPanel();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $leftPaneWidthPercent.change(async function() {
 | 
			
		||||
        await server.put('options/leftPaneWidthPercent/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        resizeLeftPanel();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function applyFontSizes() {
 | 
			
		||||
        console.log($mainFontSize.val() + "% !important");
 | 
			
		||||
 | 
			
		||||
        $body.get(0).style.setProperty("--main-font-size", $mainFontSize.val() + "%");
 | 
			
		||||
        $body.get(0).style.setProperty("--tree-font-size", $treeFontSize.val() + "%");
 | 
			
		||||
        $body.get(0).style.setProperty("--detail-font-size", $detailFontSize.val() + "%");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $mainFontSize.change(async function() {
 | 
			
		||||
        await server.put('options/mainFontSize/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        applyFontSizes();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $treeFontSize.change(async function() {
 | 
			
		||||
        await server.put('options/treeFontSize/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        applyFontSizes();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $detailFontSize.change(async function() {
 | 
			
		||||
        await server.put('options/detailFontSize/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        applyFontSizes();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        optionsLoaded
 | 
			
		||||
    };
 | 
			
		||||
})());
 | 
			
		||||
 | 
			
		||||
addTabHandler((function() {
 | 
			
		||||
    const $form = $("#change-password-form");
 | 
			
		||||
    const $oldPassword = $("#old-password");
 | 
			
		||||
    const $newPassword1 = $("#new-password1");
 | 
			
		||||
    const $newPassword2 = $("#new-password2");
 | 
			
		||||
 | 
			
		||||
    function optionsLoaded(options) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $form.submit(() => {
 | 
			
		||||
        const oldPassword = $oldPassword.val();
 | 
			
		||||
        const newPassword1 = $newPassword1.val();
 | 
			
		||||
        const newPassword2 = $newPassword2.val();
 | 
			
		||||
 | 
			
		||||
        $oldPassword.val('');
 | 
			
		||||
        $newPassword1.val('');
 | 
			
		||||
        $newPassword2.val('');
 | 
			
		||||
 | 
			
		||||
        if (newPassword1 !== newPassword2) {
 | 
			
		||||
            alert("New passwords are not the same.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        server.post('password/change', {
 | 
			
		||||
            'current_password': oldPassword,
 | 
			
		||||
            'new_password': newPassword1
 | 
			
		||||
        }).then(result => {
 | 
			
		||||
            if (result.success) {
 | 
			
		||||
                alert("Password has been changed. Trilium will be reloaded after you press OK.");
 | 
			
		||||
 | 
			
		||||
                // password changed so current protected session is invalid and needs to be cleared
 | 
			
		||||
                protectedSessionHolder.resetProtectedSession();
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                infoService.showError(result.message);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        optionsLoaded
 | 
			
		||||
    };
 | 
			
		||||
})());
 | 
			
		||||
 | 
			
		||||
addTabHandler((function() {
 | 
			
		||||
    const $form = $("#protected-session-timeout-form");
 | 
			
		||||
    const $protectedSessionTimeout = $("#protected-session-timeout-in-seconds");
 | 
			
		||||
 | 
			
		||||
    function optionsLoaded(options) {
 | 
			
		||||
        $protectedSessionTimeout.val(options['protectedSessionTimeout']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $form.submit(() => {
 | 
			
		||||
        const protectedSessionTimeout = $protectedSessionTimeout.val();
 | 
			
		||||
 | 
			
		||||
        saveOptions({ 'protectedSessionTimeout': protectedSessionTimeout }).then(() => {
 | 
			
		||||
            optionsInit.loadOptions();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        optionsLoaded
 | 
			
		||||
    };
 | 
			
		||||
})());
 | 
			
		||||
 | 
			
		||||
addTabHandler((function () {
 | 
			
		||||
    const $form = $("#note-revision-snapshot-time-interval-form");
 | 
			
		||||
    const $timeInterval = $("#note-revision-snapshot-time-interval-in-seconds");
 | 
			
		||||
 | 
			
		||||
    function optionsLoaded(options) {
 | 
			
		||||
        $timeInterval.val(options['noteRevisionSnapshotTimeInterval']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $form.submit(() => {
 | 
			
		||||
        saveOptions({ 'noteRevisionSnapshotTimeInterval': $timeInterval.val() });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        optionsLoaded
 | 
			
		||||
    };
 | 
			
		||||
})());
 | 
			
		||||
 | 
			
		||||
addTabHandler((function() {
 | 
			
		||||
    const $form = $("#sync-setup-form");
 | 
			
		||||
    const $syncServerHost = $("#sync-server-host");
 | 
			
		||||
    const $syncServerTimeout = $("#sync-server-timeout");
 | 
			
		||||
    const $syncProxy = $("#sync-proxy");
 | 
			
		||||
    const $testSyncButton = $("#test-sync-button");
 | 
			
		||||
 | 
			
		||||
    function optionsLoaded(options) {
 | 
			
		||||
        $syncServerHost.val(options['syncServerHost']);
 | 
			
		||||
        $syncServerTimeout.val(options['syncServerTimeout']);
 | 
			
		||||
        $syncProxy.val(options['syncProxy']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $form.submit(() => {
 | 
			
		||||
        saveOptions({
 | 
			
		||||
            'syncServerHost': $syncServerHost.val(),
 | 
			
		||||
            'syncServerTimeout': $syncServerTimeout.val(),
 | 
			
		||||
            'syncProxy': $syncProxy.val()
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $testSyncButton.click(async () => {
 | 
			
		||||
        const result = await server.post('sync/test');
 | 
			
		||||
 | 
			
		||||
        if (result.success) {
 | 
			
		||||
            infoService.showMessage(result.message);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            infoService.showError("Sync server handshake failed, error: " + result.message);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        optionsLoaded
 | 
			
		||||
    };
 | 
			
		||||
})());
 | 
			
		||||
 | 
			
		||||
addTabHandler((async function () {
 | 
			
		||||
    const $forceFullSyncButton = $("#force-full-sync-button");
 | 
			
		||||
    const $fillSyncRowsButton = $("#fill-sync-rows-button");
 | 
			
		||||
    const $anonymizeButton = $("#anonymize-button");
 | 
			
		||||
    const $cleanupSoftDeletedButton = $("#cleanup-soft-deleted-items-button");
 | 
			
		||||
    const $cleanupUnusedImagesButton = $("#cleanup-unused-images-button");
 | 
			
		||||
    const $vacuumDatabaseButton = $("#vacuum-database-button");
 | 
			
		||||
 | 
			
		||||
    $forceFullSyncButton.click(async () => {
 | 
			
		||||
        await server.post('sync/force-full-sync');
 | 
			
		||||
 | 
			
		||||
        infoService.showMessage("Full sync triggered");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $fillSyncRowsButton.click(async () => {
 | 
			
		||||
        await server.post('sync/fill-sync-rows');
 | 
			
		||||
 | 
			
		||||
        infoService.showMessage("Sync rows filled successfully");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    $anonymizeButton.click(async () => {
 | 
			
		||||
        await server.post('anonymization/anonymize');
 | 
			
		||||
 | 
			
		||||
        infoService.showMessage("Created anonymized database");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $cleanupSoftDeletedButton.click(async () => {
 | 
			
		||||
        if (confirm("Do you really want to clean up soft-deleted items?")) {
 | 
			
		||||
            await server.post('cleanup/cleanup-soft-deleted-items');
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Soft deleted items have been cleaned up");
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $cleanupUnusedImagesButton.click(async () => {
 | 
			
		||||
        if (confirm("Do you really want to clean up unused images?")) {
 | 
			
		||||
            await server.post('cleanup/cleanup-unused-images');
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Unused images have been cleaned up");
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $vacuumDatabaseButton.click(async () => {
 | 
			
		||||
        await server.post('cleanup/vacuum-database');
 | 
			
		||||
 | 
			
		||||
        infoService.showMessage("Database has been vacuumed");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
})());
 | 
			
		||||
 | 
			
		||||
addTabHandler((async function() {
 | 
			
		||||
    const $sidebarMinWidth = $("#sidebar-min-width");
 | 
			
		||||
    const $sidebarWidthPercent = $("#sidebar-width-percent");
 | 
			
		||||
    const $showSidebarInNewTab = $("#show-sidebar-in-new-tab");
 | 
			
		||||
    const $widgetsActive = $("#widgets-active");
 | 
			
		||||
    const $widgetsInactive = $("#widgets-inactive");
 | 
			
		||||
 | 
			
		||||
    await libraryLoader.requireLibrary(libraryLoader.SORTABLE);
 | 
			
		||||
 | 
			
		||||
    new Sortable($widgetsActive[0], {
 | 
			
		||||
        group: 'shared',
 | 
			
		||||
        animation: 150
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    new Sortable($widgetsInactive[0], {
 | 
			
		||||
        group: 'shared',
 | 
			
		||||
        animation: 150
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    async function optionsLoaded(options) {
 | 
			
		||||
        $sidebarMinWidth.val(options.sidebarMinWidth);
 | 
			
		||||
        $sidebarWidthPercent.val(options.sidebarWidthPercent);
 | 
			
		||||
 | 
			
		||||
        if (parseInt(options.showSidebarInNewTab)) {
 | 
			
		||||
            $showSidebarInNewTab.attr("checked", "checked");
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $showSidebarInNewTab.removeAttr("checked");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function resizeSidebar() {
 | 
			
		||||
        const sidebarWidthPercent = parseInt($sidebarWidthPercent.val());
 | 
			
		||||
        const sidebarMinWidth = $sidebarMinWidth.val();
 | 
			
		||||
 | 
			
		||||
        // need to find them dynamically since they change
 | 
			
		||||
        const $sidebar = $(".note-detail-sidebar");
 | 
			
		||||
 | 
			
		||||
        console.log("Resizing to ", sidebarWidthPercent, sidebarMinWidth);
 | 
			
		||||
 | 
			
		||||
        $sidebar.css("width", sidebarWidthPercent + '%');
 | 
			
		||||
        $sidebar.css("min-width", sidebarMinWidth + 'px');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $sidebarMinWidth.change(async function() {
 | 
			
		||||
        await server.put('options/sidebarMinWidth/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        resizeSidebar();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $sidebarWidthPercent.change(async function() {
 | 
			
		||||
        await server.put('options/sidebarWidthPercent/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        resizeSidebar();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $showSidebarInNewTab.change(async function() {
 | 
			
		||||
        const flag = $(this).is(":checked") ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
        await server.put('options/showSidebarInNewTab/' + flag);
 | 
			
		||||
 | 
			
		||||
        optionsInit.loadOptions();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        optionsLoaded
 | 
			
		||||
    };
 | 
			
		||||
})());
 | 
			
		||||
							
								
								
									
										53
									
								
								src/public/javascripts/dialogs/options/advanced.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/public/javascripts/dialogs/options/advanced.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import infoService from "../../services/info.js";
 | 
			
		||||
 | 
			
		||||
export default class AdvancedOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$forceFullSyncButton = $("#force-full-sync-button");
 | 
			
		||||
        this.$fillSyncRowsButton = $("#fill-sync-rows-button");
 | 
			
		||||
        this.$anonymizeButton = $("#anonymize-button");
 | 
			
		||||
        this.$cleanupSoftDeletedButton = $("#cleanup-soft-deleted-items-button");
 | 
			
		||||
        this.$cleanupUnusedImagesButton = $("#cleanup-unused-images-button");
 | 
			
		||||
        this.$vacuumDatabaseButton = $("#vacuum-database-button");
 | 
			
		||||
 | 
			
		||||
        this.$forceFullSyncButton.click(async () => {
 | 
			
		||||
            await server.post('sync/force-full-sync');
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Full sync triggered");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$fillSyncRowsButton.click(async () => {
 | 
			
		||||
            await server.post('sync/fill-sync-rows');
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Sync rows filled successfully");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$anonymizeButton.click(async () => {
 | 
			
		||||
            await server.post('anonymization/anonymize');
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Created anonymized database");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$cleanupSoftDeletedButton.click(async () => {
 | 
			
		||||
            if (confirm("Do you really want to clean up soft-deleted items?")) {
 | 
			
		||||
                await server.post('cleanup/cleanup-soft-deleted-items');
 | 
			
		||||
 | 
			
		||||
                infoService.showMessage("Soft deleted items have been cleaned up");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$cleanupUnusedImagesButton.click(async () => {
 | 
			
		||||
            if (confirm("Do you really want to clean up unused images?")) {
 | 
			
		||||
                await server.post('cleanup/cleanup-unused-images');
 | 
			
		||||
 | 
			
		||||
                infoService.showMessage("Unused images have been cleaned up");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$vacuumDatabaseButton.click(async () => {
 | 
			
		||||
            await server.post('cleanup/vacuum-database');
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Database has been vacuumed");
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										130
									
								
								src/public/javascripts/dialogs/options/appearance.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/public/javascripts/dialogs/options/appearance.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import utils from "../../services/utils.js";
 | 
			
		||||
import cssLoader from "../../services/css_loader.js";
 | 
			
		||||
import zoomService from "../../services/zoom.js";
 | 
			
		||||
import optionsInit from "../../services/options_init.js";
 | 
			
		||||
 | 
			
		||||
export default class ApperanceOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$themeSelect = $("#theme-select");
 | 
			
		||||
        this.$zoomFactorSelect = $("#zoom-factor-select");
 | 
			
		||||
        this.$oneTabDisplaySelect = $("#one-tab-display-select");
 | 
			
		||||
        this.$leftPaneMinWidth = $("#left-pane-min-width");
 | 
			
		||||
        this.$leftPaneWidthPercent = $("#left-pane-width-percent");
 | 
			
		||||
        this.$mainFontSize = $("#main-font-size");
 | 
			
		||||
        this.$treeFontSize = $("#tree-font-size");
 | 
			
		||||
        this.$detailFontSize = $("#detail-font-size");
 | 
			
		||||
        this.$body = $("body");
 | 
			
		||||
        this.$container = $("#container");
 | 
			
		||||
 | 
			
		||||
        this.$themeSelect.change(() => {
 | 
			
		||||
            const newTheme = this.$themeSelect.val();
 | 
			
		||||
 | 
			
		||||
            for (const clazz of Array.from(this.$body[0].classList)) { // create copy to safely iterate over while removing classes
 | 
			
		||||
                if (clazz.startsWith("theme-")) {
 | 
			
		||||
                    this.$body.removeClass(clazz);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const noteId = $(this).find(":selected").attr("data-note-id");
 | 
			
		||||
 | 
			
		||||
            if (noteId) {
 | 
			
		||||
                // make sure the CSS is loaded
 | 
			
		||||
                // if the CSS has been loaded and then updated then the changes won't take effect though
 | 
			
		||||
                cssLoader.requireCss(`/api/notes/download/${noteId}`);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.$body.addClass("theme-" + newTheme);
 | 
			
		||||
 | 
			
		||||
            server.put('options/theme/' + newTheme);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$zoomFactorSelect.change(() => { zoomService.setZoomFactorAndSave(this.$zoomFactorSelect.val()); });
 | 
			
		||||
 | 
			
		||||
        this.$oneTabDisplaySelect.change(() => {
 | 
			
		||||
            const hideTabRowForOneTab = this.$oneTabDisplaySelect.val() === 'hide' ? 'true' : 'false';
 | 
			
		||||
 | 
			
		||||
            server.put('options/hideTabRowForOneTab/' + hideTabRowForOneTab)
 | 
			
		||||
                .then(optionsInit.loadOptions);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$leftPaneMinWidth.change(async () => {
 | 
			
		||||
            await server.put('options/leftPaneMinWidth/' + this.$leftPaneMinWidth.val());
 | 
			
		||||
 | 
			
		||||
            this.resizeLeftPanel();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$leftPaneWidthPercent.change(async () => {
 | 
			
		||||
            await server.put('options/leftPaneWidthPercent/' + this.$leftPaneWidthPercent.val());
 | 
			
		||||
 | 
			
		||||
            this.resizeLeftPanel();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$mainFontSize.change(async () => {
 | 
			
		||||
            await server.put('options/mainFontSize/' + this.$mainFontSize.val());
 | 
			
		||||
 | 
			
		||||
            this.applyFontSizes();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$treeFontSize.change(async () => {
 | 
			
		||||
            await server.put('options/treeFontSize/' + this.$treeFontSize.val());
 | 
			
		||||
 | 
			
		||||
            this.applyFontSizes();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$detailFontSize.change(async () => {
 | 
			
		||||
            await server.put('options/detailFontSize/' + this.$detailFontSize.val());
 | 
			
		||||
 | 
			
		||||
            this.applyFontSizes();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async optionsLoaded(options) {
 | 
			
		||||
        const themes = [
 | 
			
		||||
            { val: 'white', title: 'White' },
 | 
			
		||||
            { val: 'dark', title: 'Dark' },
 | 
			
		||||
            { val: 'black', title: 'Black' }
 | 
			
		||||
        ].concat(await server.get('options/user-themes'));
 | 
			
		||||
 | 
			
		||||
        this.$themeSelect.empty();
 | 
			
		||||
 | 
			
		||||
        for (const theme of themes) {
 | 
			
		||||
            this.$themeSelect.append($("<option>")
 | 
			
		||||
                .attr("value", theme.val)
 | 
			
		||||
                .attr("data-note-id", theme.noteId)
 | 
			
		||||
                .html(theme.title));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$themeSelect.val(options.theme);
 | 
			
		||||
 | 
			
		||||
        if (utils.isElectron()) {
 | 
			
		||||
            this.$zoomFactorSelect.val(options.zoomFactor);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            this.$zoomFactorSelect.prop('disabled', true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$oneTabDisplaySelect.val(options.hideTabRowForOneTab === 'true' ? 'hide' : 'show');
 | 
			
		||||
 | 
			
		||||
        this.$leftPaneMinWidth.val(options.leftPaneMinWidth);
 | 
			
		||||
        this.$leftPaneWidthPercent.val(options.leftPaneWidthPercent);
 | 
			
		||||
 | 
			
		||||
        this.$mainFontSize.val(options.mainFontSize);
 | 
			
		||||
        this.$treeFontSize.val(options.treeFontSize);
 | 
			
		||||
        this.$detailFontSize.val(options.detailFontSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    resizeLeftPanel() {
 | 
			
		||||
        const leftPanePercent = parseInt(this.$leftPaneWidthPercent.val());
 | 
			
		||||
        const rightPanePercent = 100 - leftPanePercent;
 | 
			
		||||
        const leftPaneMinWidth = this.$leftPaneMinWidth.val();
 | 
			
		||||
 | 
			
		||||
        this.$container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    applyFontSizes() {
 | 
			
		||||
        this.$body.get(0).style.setProperty("--main-font-size", this.$mainFontSize.val() + "%");
 | 
			
		||||
        this.$body.get(0).style.setProperty("--tree-font-size", this.$treeFontSize.val() + "%");
 | 
			
		||||
        this.$body.get(0).style.setProperty("--detail-font-size", this.$detailFontSize.val() + "%");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/public/javascripts/dialogs/options/change_password.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/public/javascripts/dialogs/options/change_password.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import protectedSessionHolder from "../../services/protected_session_holder.js";
 | 
			
		||||
import infoService from "../../services/info.js";
 | 
			
		||||
 | 
			
		||||
export default class ChangePasswordOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$form = $("#change-password-form");
 | 
			
		||||
        this.$oldPassword = $("#old-password");
 | 
			
		||||
        this.$newPassword1 = $("#new-password1");
 | 
			
		||||
        this.$newPassword2 = $("#new-password2");
 | 
			
		||||
 | 
			
		||||
        this.$form.submit(() => this.save());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optionsLoaded(options) {}
 | 
			
		||||
 | 
			
		||||
    save() {
 | 
			
		||||
        const oldPassword = this.$oldPassword.val();
 | 
			
		||||
        const newPassword1 = this.$newPassword1.val();
 | 
			
		||||
        const newPassword2 = this.$newPassword2.val();
 | 
			
		||||
 | 
			
		||||
        this.$oldPassword.val('');
 | 
			
		||||
        this.$newPassword1.val('');
 | 
			
		||||
        this.$newPassword2.val('');
 | 
			
		||||
 | 
			
		||||
        if (newPassword1 !== newPassword2) {
 | 
			
		||||
            alert("New passwords are not the same.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        server.post('password/change', {
 | 
			
		||||
            'current_password': oldPassword,
 | 
			
		||||
            'new_password': newPassword1
 | 
			
		||||
        }).then(result => {
 | 
			
		||||
            if (result.success) {
 | 
			
		||||
                alert("Password has been changed. Trilium will be reloaded after you press OK.");
 | 
			
		||||
 | 
			
		||||
                // password changed so current protected session is invalid and needs to be cleared
 | 
			
		||||
                protectedSessionHolder.resetProtectedSession();
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                infoService.showError(result.message);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/public/javascripts/dialogs/options/note_revisions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/public/javascripts/dialogs/options/note_revisions.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import infoService from "../../services/info.js";
 | 
			
		||||
 | 
			
		||||
export default class NoteRevisionsOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$form = $("#note-revision-snapshot-time-interval-form");
 | 
			
		||||
        this.$timeInterval = $("#note-revision-snapshot-time-interval-in-seconds");
 | 
			
		||||
 | 
			
		||||
        this.$form.submit(() => {
 | 
			
		||||
            const opts = { 'noteRevisionSnapshotTimeInterval': this.$timeInterval.val() };
 | 
			
		||||
            server.put('options', opts).then(() => infoService.showMessage("Options change have been saved."));
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optionsLoaded(options) {
 | 
			
		||||
        this.$timeInterval.val(options['noteRevisionSnapshotTimeInterval']);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								src/public/javascripts/dialogs/options/protected_session.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/public/javascripts/dialogs/options/protected_session.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import optionsInit from "../../services/options_init.js";
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import infoService from "../../services/info.js";
 | 
			
		||||
 | 
			
		||||
export default class ProtectedSessionOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$form = $("#protected-session-timeout-form");
 | 
			
		||||
        this.$protectedSessionTimeout = $("#protected-session-timeout-in-seconds");
 | 
			
		||||
 | 
			
		||||
        this.$form.submit(() => this.save());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optionsLoaded(options) {
 | 
			
		||||
        this.$protectedSessionTimeout.val(options['protectedSessionTimeout']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    save() {
 | 
			
		||||
        const protectedSessionTimeout = this.$protectedSessionTimeout.val();
 | 
			
		||||
 | 
			
		||||
        server.put('options', { 'protectedSessionTimeout': protectedSessionTimeout }).then(() => {
 | 
			
		||||
            optionsInit.loadOptions();
 | 
			
		||||
 | 
			
		||||
            infoService.showMessage("Options change have been saved.");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								src/public/javascripts/dialogs/options/sidebar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/public/javascripts/dialogs/options/sidebar.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
import libraryLoader from "../../services/library_loader.js";
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import optionsInit from "../../services/options_init.js";
 | 
			
		||||
 | 
			
		||||
export default class SidebarOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$sidebarMinWidth = $("#sidebar-min-width");
 | 
			
		||||
        this.$sidebarWidthPercent = $("#sidebar-width-percent");
 | 
			
		||||
        this.$showSidebarInNewTab = $("#show-sidebar-in-new-tab");
 | 
			
		||||
        this.$widgetsActive = $("#widgets-active");
 | 
			
		||||
        this.$widgetsInactive = $("#widgets-inactive");
 | 
			
		||||
 | 
			
		||||
        libraryLoader.requireLibrary(libraryLoader.SORTABLE).then(() => {
 | 
			
		||||
            new Sortable(this.$widgetsActive[0], {
 | 
			
		||||
                group: 'shared',
 | 
			
		||||
                animation: 150
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            new Sortable(this.$widgetsInactive[0], {
 | 
			
		||||
                group: 'shared',
 | 
			
		||||
                animation: 150
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$sidebarMinWidth.change(async () => {
 | 
			
		||||
            await server.put('options/sidebarMinWidth/' + this.$sidebarMinWidth.val());
 | 
			
		||||
 | 
			
		||||
            this.resizeSidebar();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$sidebarWidthPercent.change(async () => {
 | 
			
		||||
            await server.put('options/sidebarWidthPercent/' + this.$sidebarWidthPercent.val());
 | 
			
		||||
 | 
			
		||||
            this.resizeSidebar();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$showSidebarInNewTab.change(async () => {
 | 
			
		||||
            const flag = this.$showSidebarInNewTab.is(":checked") ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
            await server.put('options/showSidebarInNewTab/' + flag);
 | 
			
		||||
 | 
			
		||||
            optionsInit.loadOptions();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async optionsLoaded(options) {
 | 
			
		||||
        this.$sidebarMinWidth.val(options.sidebarMinWidth);
 | 
			
		||||
        this.$sidebarWidthPercent.val(options.sidebarWidthPercent);
 | 
			
		||||
 | 
			
		||||
        if (parseInt(options.showSidebarInNewTab)) {
 | 
			
		||||
            this.$showSidebarInNewTab.attr("checked", "checked");
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            this.$showSidebarInNewTab.removeAttr("checked");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    resizeSidebar() {
 | 
			
		||||
        const sidebarWidthPercent = parseInt(this.$sidebarWidthPercent.val());
 | 
			
		||||
        const sidebarMinWidth = this.$sidebarMinWidth.val();
 | 
			
		||||
 | 
			
		||||
        // need to find them dynamically since they change
 | 
			
		||||
        const $sidebar = $(".note-detail-sidebar");
 | 
			
		||||
 | 
			
		||||
        $sidebar.css("width", sidebarWidthPercent + '%');
 | 
			
		||||
        $sidebar.css("min-width", sidebarMinWidth + 'px');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								src/public/javascripts/dialogs/options/sync.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/public/javascripts/dialogs/options/sync.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import infoService from "../../services/info.js";
 | 
			
		||||
 | 
			
		||||
export default class SyncOptions {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.$form = $("#sync-setup-form");
 | 
			
		||||
        this.$syncServerHost = $("#sync-server-host");
 | 
			
		||||
        this.$syncServerTimeout = $("#sync-server-timeout");
 | 
			
		||||
        this.$syncProxy = $("#sync-proxy");
 | 
			
		||||
        this.$testSyncButton = $("#test-sync-button");
 | 
			
		||||
 | 
			
		||||
        this.$form.submit(() => this.save());
 | 
			
		||||
 | 
			
		||||
        this.$testSyncButton.click(async () => {
 | 
			
		||||
            const result = await server.post('sync/test');
 | 
			
		||||
 | 
			
		||||
            if (result.success) {
 | 
			
		||||
                infoService.showMessage(result.message);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                infoService.showError("Sync server handshake failed, error: " + result.message);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optionsLoaded(options) {
 | 
			
		||||
        this.$syncServerHost.val(options['syncServerHost']);
 | 
			
		||||
        this.$syncServerTimeout.val(options['syncServerTimeout']);
 | 
			
		||||
        this.$syncProxy.val(options['syncProxy']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    save() {
 | 
			
		||||
        const opts = {
 | 
			
		||||
            'syncServerHost': this.$syncServerHost.val(),
 | 
			
		||||
            'syncServerTimeout': this.$syncServerTimeout.val(),
 | 
			
		||||
            'syncProxy': this.$syncProxy.val()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        server.put('options', opts).then(()  => infoService.showMessage("Options change have been saved."));
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -53,13 +53,13 @@ class Sidebar {
 | 
			
		||||
        this.widgets = [];
 | 
			
		||||
        this.$widgetContainer.empty();
 | 
			
		||||
 | 
			
		||||
        const widgetClasses = [
 | 
			
		||||
            await import("../widgets/note_info.js"),
 | 
			
		||||
            await import("../widgets/link_map.js"),
 | 
			
		||||
            await import("../widgets/note_revisions.js"),
 | 
			
		||||
            await import("../widgets/attributes.js"),
 | 
			
		||||
            await import("../widgets/what_links_here.js")
 | 
			
		||||
        ].map(m => m.default);
 | 
			
		||||
        const widgetClasses = (await Promise.all([
 | 
			
		||||
            import("../widgets/note_info.js"),
 | 
			
		||||
            import("../widgets/link_map.js"),
 | 
			
		||||
            import("../widgets/note_revisions.js"),
 | 
			
		||||
            import("../widgets/attributes.js"),
 | 
			
		||||
            import("../widgets/what_links_here.js")
 | 
			
		||||
        ])).map(m => m.default);
 | 
			
		||||
 | 
			
		||||
        const widgetRelations = await this.ctx.note.getRelations('widget');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user