mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 13:39:01 +01:00 
			
		
		
		
	add a button to temporarily hide TOC, closes #3555
This commit is contained in:
		
							parent
							
								
									64e7150765
								
							
						
					
					
						commit
						a7b103e07a
					
				@ -15,6 +15,8 @@ class NoteContext extends Component {
 | 
			
		||||
        this.ntxId = ntxId || utils.randomString(4);
 | 
			
		||||
        this.hoistedNoteId = hoistedNoteId;
 | 
			
		||||
        this.mainNtxId = mainNtxId;
 | 
			
		||||
 | 
			
		||||
        this.resetViewScope();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setEmpty() {
 | 
			
		||||
@ -27,6 +29,8 @@ class NoteContext extends Component {
 | 
			
		||||
            noteContext: this,
 | 
			
		||||
            notePath: this.notePath
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.resetViewScope();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isEmpty() {
 | 
			
		||||
@ -47,7 +51,7 @@ class NoteContext extends Component {
 | 
			
		||||
        this.notePath = resolvedNotePath;
 | 
			
		||||
        ({noteId: this.noteId, parentNoteId: this.parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(resolvedNotePath));
 | 
			
		||||
 | 
			
		||||
        this.readOnlyTemporarilyDisabled = false;
 | 
			
		||||
        this.resetViewScope();
 | 
			
		||||
 | 
			
		||||
        this.saveToRecentNotes(resolvedNotePath);
 | 
			
		||||
 | 
			
		||||
@ -60,6 +64,14 @@ class NoteContext extends Component {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await this.setHoistedNoteIfNeeded();
 | 
			
		||||
 | 
			
		||||
        if (utils.isMobile()) {
 | 
			
		||||
            this.triggerCommand('setActiveScreen', {screen: 'detail'});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async setHoistedNoteIfNeeded() {
 | 
			
		||||
        if (this.hoistedNoteId === 'root'
 | 
			
		||||
            && this.notePath.startsWith("root/_hidden")
 | 
			
		||||
            && !this.note.hasLabel("keepCurrentHoisting")
 | 
			
		||||
@ -76,10 +88,6 @@ class NoteContext extends Component {
 | 
			
		||||
 | 
			
		||||
            await this.setHoistedNoteId(hoistedNoteId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (utils.isMobile()) {
 | 
			
		||||
            this.triggerCommand('setActiveScreen', {screen: 'detail'});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getSubContexts() {
 | 
			
		||||
@ -201,7 +209,7 @@ class NoteContext extends Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async isReadOnly() {
 | 
			
		||||
        if (this.readOnlyTemporarilyDisabled) {
 | 
			
		||||
        if (this.viewScope.readOnlyTemporarilyDisabled) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -277,6 +285,13 @@ class NoteContext extends Component {
 | 
			
		||||
            ntxId: this.ntxId
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    resetViewScope() {
 | 
			
		||||
        // view scope contains data specific to one note context and one "view".
 | 
			
		||||
        // it is used to e.g. make read-only note temporarily editable or to hide TOC
 | 
			
		||||
        // this is reset after navigating to a different note
 | 
			
		||||
        this.viewScope = {};
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default NoteContext;
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ import froca from "../services/froca.js";
 | 
			
		||||
export default class RootCommandExecutor extends Component {
 | 
			
		||||
    editReadOnlyNoteCommand() {
 | 
			
		||||
        const noteContext = appContext.tabManager.getActiveContext();
 | 
			
		||||
        noteContext.readOnlyTemporarilyDisabled = true;
 | 
			
		||||
        noteContext.viewScope.readOnlyTemporarilyDisabled = true;
 | 
			
		||||
 | 
			
		||||
        appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ export default class EditButton extends OnClickButtonWidget {
 | 
			
		||||
            .title("Edit this note")
 | 
			
		||||
            .titlePlacement("bottom")
 | 
			
		||||
            .onClick(widget => {
 | 
			
		||||
                this.noteContext.readOnlyTemporarilyDisabled = true;
 | 
			
		||||
                this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
 | 
			
		||||
 | 
			
		||||
                appContext.triggerEvent('readOnlyTemporarilyDisabled', {noteContext: this.noteContext});
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,7 @@ export default class EditButton extends OnClickButtonWidget {
 | 
			
		||||
                && attr.name.toLowerCase().includes("readonly")
 | 
			
		||||
                && attributeService.isAffecting(attr, this.note)
 | 
			
		||||
        )) {
 | 
			
		||||
            this.noteContext.readOnlyTemporarilyDisabled = false;
 | 
			
		||||
            this.noteContext.viewScope.readOnlyTemporarilyDisabled = false;
 | 
			
		||||
 | 
			
		||||
            this.refresh();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -24,17 +24,17 @@ export default class RightPaneContainer extends FlexContainer {
 | 
			
		||||
            // we'll reevaluate the visibility based on events which are probable to cause visibility change
 | 
			
		||||
            // but these events needs to be finished and only then we check
 | 
			
		||||
            if (promise) {
 | 
			
		||||
                promise.then(() => this.reevaluateIsEnabledCommand());
 | 
			
		||||
                promise.then(() => this.reEvaluateRightPaneVisibilityCommand());
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                this.reevaluateIsEnabledCommand();
 | 
			
		||||
                this.reEvaluateRightPaneVisibilityCommand();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    reevaluateIsEnabledCommand() {
 | 
			
		||||
    reEvaluateRightPaneVisibilityCommand() {
 | 
			
		||||
        const oldToggle = !this.isHiddenInt();
 | 
			
		||||
        const newToggle = this.isEnabled();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@
 | 
			
		||||
import attributeService from "../services/attributes.js";
 | 
			
		||||
import RightPanelWidget from "./right_panel_widget.js";
 | 
			
		||||
import options from "../services/options.js";
 | 
			
		||||
import OnClickButtonWidget from "./buttons/onclick_button.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `<div class="toc-widget">
 | 
			
		||||
    <style>
 | 
			
		||||
@ -24,6 +25,7 @@ const TPL = `<div class="toc-widget">
 | 
			
		||||
            padding: 10px;
 | 
			
		||||
            contain: none; 
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            position: relative;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .toc ol {
 | 
			
		||||
@ -41,53 +43,39 @@ const TPL = `<div class="toc-widget">
 | 
			
		||||
        .toc li:hover {
 | 
			
		||||
            font-weight: bold;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .close-toc {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: 2px;
 | 
			
		||||
            right: 2px;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <span class="toc"></span>
 | 
			
		||||
</div>`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find a heading node in the parent's children given its index.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Element} parent Parent node to find a headingIndex'th in.
 | 
			
		||||
 * @param {uint} headingIndex Index for the heading
 | 
			
		||||
 * @returns {Element|null} Heading node with the given index, null couldn't be
 | 
			
		||||
 *          found (ie malformed like nested headings, etc.)
 | 
			
		||||
 */
 | 
			
		||||
function findHeadingNodeByIndex(parent, headingIndex) {
 | 
			
		||||
    let headingNode = null;
 | 
			
		||||
    for (let i = 0; i < parent.childCount; ++i) {
 | 
			
		||||
        let child = parent.getChild(i);
 | 
			
		||||
export default class TocWidget extends RightPanelWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        // Headings appear as flattened top level children in the CKEditor
 | 
			
		||||
        // document named as "heading" plus the level, eg "heading2",
 | 
			
		||||
        // "heading3", "heading2", etc. and not nested wrt the heading level. If
 | 
			
		||||
        // a heading node is found, decrement the headingIndex until zero is
 | 
			
		||||
        // reached
 | 
			
		||||
        if (child.name.startsWith("heading")) {
 | 
			
		||||
            if (headingIndex === 0) {
 | 
			
		||||
                headingNode = child;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            headingIndex--;
 | 
			
		||||
        }
 | 
			
		||||
        this.closeTocButton = new CloseTocButton();
 | 
			
		||||
        this.child(this.closeTocButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return headingNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class TocWidget extends RightPanelWidget {
 | 
			
		||||
    get widgetTitle() {
 | 
			
		||||
        return "Table of Contents";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isEnabled() {
 | 
			
		||||
        return super.isEnabled() && this.note.type === 'text';
 | 
			
		||||
        return super.isEnabled()
 | 
			
		||||
            && this.note.type === 'text'
 | 
			
		||||
            && !this.noteContext.viewScope.tocTemporarilyHidden;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async doRenderBody() {
 | 
			
		||||
        this.$body.empty().append($(TPL));
 | 
			
		||||
        this.$toc = this.$body.find('.toc');
 | 
			
		||||
        this.$body.find('.toc-widget').append(this.closeTocButton.render());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async refreshWithNote(note) {
 | 
			
		||||
@ -95,7 +83,7 @@ export default class TocWidget extends RightPanelWidget {
 | 
			
		||||
 | 
			
		||||
        if (tocLabel?.value === 'hide') {
 | 
			
		||||
            this.toggleInt(false);
 | 
			
		||||
            this.triggerCommand("reevaluateIsEnabled");
 | 
			
		||||
            this.triggerCommand("reEvaluateRightPaneVisibility");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -112,7 +100,7 @@ export default class TocWidget extends RightPanelWidget {
 | 
			
		||||
            || headingCount >= options.getInt('minTocHeadings')
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        this.triggerCommand("reevaluateIsEnabled");
 | 
			
		||||
        this.triggerCommand("reEvaluateRightPaneVisibility");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -252,6 +240,12 @@ export default class TocWidget extends RightPanelWidget {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async closeTocCommand() {
 | 
			
		||||
        this.noteContext.viewScope.tocTemporarilyHidden = true;
 | 
			
		||||
        await this.refresh();
 | 
			
		||||
        this.triggerCommand('reEvaluateRightPaneVisibility');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async entitiesReloadedEvent({loadResults}) {
 | 
			
		||||
        if (loadResults.isNoteContentReloaded(this.noteId)) {
 | 
			
		||||
            await this.refresh();
 | 
			
		||||
@ -263,3 +257,49 @@ export default class TocWidget extends RightPanelWidget {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find a heading node in the parent's children given its index.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Element} parent Parent node to find a headingIndex'th in.
 | 
			
		||||
 * @param {uint} headingIndex Index for the heading
 | 
			
		||||
 * @returns {Element|null} Heading node with the given index, null couldn't be
 | 
			
		||||
 *          found (ie malformed like nested headings, etc.)
 | 
			
		||||
 */
 | 
			
		||||
function findHeadingNodeByIndex(parent, headingIndex) {
 | 
			
		||||
    let headingNode = null;
 | 
			
		||||
    for (let i = 0; i < parent.childCount; ++i) {
 | 
			
		||||
        let child = parent.getChild(i);
 | 
			
		||||
 | 
			
		||||
        // Headings appear as flattened top level children in the CKEditor
 | 
			
		||||
        // document named as "heading" plus the level, eg "heading2",
 | 
			
		||||
        // "heading3", "heading2", etc. and not nested wrt the heading level. If
 | 
			
		||||
        // a heading node is found, decrement the headingIndex until zero is
 | 
			
		||||
        // reached
 | 
			
		||||
        if (child.name.startsWith("heading")) {
 | 
			
		||||
            if (headingIndex === 0) {
 | 
			
		||||
                headingNode = child;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            headingIndex--;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return headingNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class CloseTocButton extends OnClickButtonWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.icon("bx-x")
 | 
			
		||||
            .title("Close TOC")
 | 
			
		||||
            .titlePlacement("bottom")
 | 
			
		||||
            .onClick((widget, e) => {
 | 
			
		||||
                e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
                widget.triggerCommand("closeToc");
 | 
			
		||||
            })
 | 
			
		||||
            .class("icon-action close-toc");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user