mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 13:39:01 +01:00 
			
		
		
		
	getting rid of attributes like data-note-path in favor of the whole nav state in URLs
This commit is contained in:
		
							parent
							
								
									291f0e79d9
								
							
						
					
					
						commit
						f85209a72f
					
				@ -9,6 +9,7 @@ import TabManager from "./tab_manager.js";
 | 
			
		||||
import treeService from "../services/tree.js";
 | 
			
		||||
import Component from "./component.js";
 | 
			
		||||
import keyboardActionsService from "../services/keyboard_actions.js";
 | 
			
		||||
import linkService from "../services/link.js";
 | 
			
		||||
import MobileScreenSwitcherExecutor from "./mobile_screen_switcher.js";
 | 
			
		||||
import MainTreeExecutors from "./main_tree_executors.js";
 | 
			
		||||
import toast from "../services/toast.js";
 | 
			
		||||
@ -158,14 +159,9 @@ $(window).on('beforeunload', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$(window).on('hashchange', function() {
 | 
			
		||||
    if (treeService.isNotePathInAddress()) {
 | 
			
		||||
        const {notePath, ntxId, viewScope} = treeService.parseNavigationStateFromAddress();
 | 
			
		||||
 | 
			
		||||
        if (!notePath && !ntxId) {
 | 
			
		||||
            console.log(`Invalid hash value "${document.location.hash}", ignoring.`);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    const {notePath, ntxId, viewScope} = linkService.parseNavigationStateFromUrl(window.location.href);
 | 
			
		||||
 | 
			
		||||
    if (notePath || ntxId) {
 | 
			
		||||
        appContext.tabManager.switchToNoteContext(ntxId, notePath, viewScope);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -52,14 +52,13 @@ export default class TabManager extends Component {
 | 
			
		||||
 | 
			
		||||
    async loadTabs() {
 | 
			
		||||
        try {
 | 
			
		||||
            const noteContextsToOpen = appContext.isMainWindow
 | 
			
		||||
                ? (options.getJson('openNoteContexts') || [])
 | 
			
		||||
                : [];
 | 
			
		||||
            const noteContextsToOpen = (appContext.isMainWindow && options.getJson('openNoteContexts')) || [];
 | 
			
		||||
 | 
			
		||||
            // preload all notes at once
 | 
			
		||||
            await froca.getNotes([
 | 
			
		||||
                    ...noteContextsToOpen.map(tab => treeService.getNoteIdFromNotePath(tab.notePath)),
 | 
			
		||||
                    ...noteContextsToOpen.map(tab => tab.hoistedNoteId),
 | 
			
		||||
                    ...noteContextsToOpen.flatMap(tab =>
 | 
			
		||||
                        [ treeService.getNoteIdFromNotePath(tab.notePath), tab.hoistedNoteId]
 | 
			
		||||
                    ),
 | 
			
		||||
            ], true);
 | 
			
		||||
 | 
			
		||||
            const filteredNoteContexts = noteContextsToOpen.filter(openTab => {
 | 
			
		||||
@ -81,7 +80,7 @@ export default class TabManager extends Component {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // resolve before opened tabs can change this
 | 
			
		||||
            const parsedFromUrl = treeService.parseNavigationStateFromAddress();
 | 
			
		||||
            const parsedFromUrl = linkService.parseNavigationStateFromUrl(window.location.href);
 | 
			
		||||
 | 
			
		||||
            if (filteredNoteContexts.length === 0) {
 | 
			
		||||
                parsedFromUrl.ntxId = parsedFromUrl.ntxId || NoteContext.generateNtxId(); // generate already here, so that we later know which one to activate
 | 
			
		||||
@ -109,8 +108,8 @@ export default class TabManager extends Component {
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // if there's notePath in the URL, make sure it's open and active
 | 
			
		||||
            // (useful, for e.g. opening clipped notes from clipper or opening link in an extra window)
 | 
			
		||||
            // if there's a notePath in the URL, make sure it's open and active
 | 
			
		||||
            // (useful, for e.g., opening clipped notes from clipper or opening link in an extra window)
 | 
			
		||||
            if (parsedFromUrl.notePath) {
 | 
			
		||||
                await appContext.tabManager.switchToNoteContext(
 | 
			
		||||
                    parsedFromUrl.ntxId,
 | 
			
		||||
 | 
			
		||||
@ -56,8 +56,7 @@ async function createNoteLink(noteId) {
 | 
			
		||||
 | 
			
		||||
    return $("<a>", {
 | 
			
		||||
        href: `#root/${noteId}`,
 | 
			
		||||
        class: 'reference-link',
 | 
			
		||||
        'data-note-path': noteId
 | 
			
		||||
        class: 'reference-link'
 | 
			
		||||
    })
 | 
			
		||||
        .text(note.title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,21 +19,17 @@ async function createNoteLink(notePath, options = {}) {
 | 
			
		||||
 | 
			
		||||
    if (!notePath.startsWith("root")) {
 | 
			
		||||
        // all note paths should start with "root/" (except for "root" itself)
 | 
			
		||||
        // used e.g., to find internal links
 | 
			
		||||
        // used, e.g., to find internal links
 | 
			
		||||
        notePath = `root/${notePath}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let noteTitle = options.title;
 | 
			
		||||
    const showTooltip = options.showTooltip === undefined ? true : options.showTooltip;
 | 
			
		||||
    const showNotePath = options.showNotePath === undefined ? false : options.showNotePath;
 | 
			
		||||
    const showNoteIcon = options.showNoteIcon === undefined ? false : options.showNoteIcon;
 | 
			
		||||
    const referenceLink = options.referenceLink === undefined ? false : options.referenceLink;
 | 
			
		||||
 | 
			
		||||
    const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
 | 
			
		||||
    if (!noteTitle) {
 | 
			
		||||
        noteTitle = await treeService.getNoteTitle(noteId, parentNoteId);
 | 
			
		||||
    }
 | 
			
		||||
    const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
    const noteTitle = options.title || await treeService.getNoteTitle(noteId, parentNoteId);
 | 
			
		||||
 | 
			
		||||
    const $container = $("<span>");
 | 
			
		||||
 | 
			
		||||
@ -45,11 +41,15 @@ async function createNoteLink(notePath, options = {}) {
 | 
			
		||||
            .append(" ");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const hash = calculateHash({
 | 
			
		||||
        notePath,
 | 
			
		||||
        viewScope: options.viewScope
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const $noteLink = $("<a>", {
 | 
			
		||||
        href: `#${notePath}`,
 | 
			
		||||
        href: hash,
 | 
			
		||||
        text: noteTitle
 | 
			
		||||
    }).attr('data-action', 'note')
 | 
			
		||||
        .attr('data-note-path', notePath);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!showTooltip) {
 | 
			
		||||
        $noteLink.addClass("no-tooltip-preview");
 | 
			
		||||
@ -78,27 +78,6 @@ async function createNoteLink(notePath, options = {}) {
 | 
			
		||||
    return $container;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parseNotePathAndScope($link) {
 | 
			
		||||
    let notePath = $link.attr("data-note-path");
 | 
			
		||||
 | 
			
		||||
    if (!notePath) {
 | 
			
		||||
        const url = $link.attr('href');
 | 
			
		||||
 | 
			
		||||
        notePath = url ? getNotePathFromUrl(url) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const viewScope = {
 | 
			
		||||
        viewMode: $link.attr('data-view-mode') || 'default',
 | 
			
		||||
        attachmentId: $link.attr('data-attachment-id'),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        notePath,
 | 
			
		||||
        noteId: treeService.getNoteIdFromNotePath(notePath),
 | 
			
		||||
        viewScope
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function calculateHash({notePath, ntxId, hoistedNoteId, viewScope = {}}) {
 | 
			
		||||
    notePath = notePath || "";
 | 
			
		||||
    const params = [
 | 
			
		||||
@ -128,9 +107,50 @@ function calculateHash({notePath, ntxId, hoistedNoteId, viewScope = {}}) {
 | 
			
		||||
    return hash;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parseNavigationStateFromUrl(url) {
 | 
			
		||||
    const hashIdx = url?.indexOf('#');
 | 
			
		||||
    if (hashIdx === -1) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const hash = url?.substr(hashIdx + 1); // strip also the initial '#'
 | 
			
		||||
    const [notePath, paramString] = hash.split("?");
 | 
			
		||||
    const viewScope = {
 | 
			
		||||
        viewMode: 'default'
 | 
			
		||||
    };
 | 
			
		||||
    let ntxId = null;
 | 
			
		||||
    let hoistedNoteId = null;
 | 
			
		||||
 | 
			
		||||
    if (paramString) {
 | 
			
		||||
        for (const pair of paramString.split("&")) {
 | 
			
		||||
            let [name, value] = pair.split("=");
 | 
			
		||||
            name = decodeURIComponent(name);
 | 
			
		||||
            value = decodeURIComponent(value);
 | 
			
		||||
 | 
			
		||||
            if (name === 'ntxId') {
 | 
			
		||||
                ntxId = value;
 | 
			
		||||
            } else if (name === 'hoistedNoteId') {
 | 
			
		||||
                hoistedNoteId = value;
 | 
			
		||||
            } else if (['viewMode', 'attachmentId'].includes(name)) {
 | 
			
		||||
                viewScope[name] = value;
 | 
			
		||||
            } else {
 | 
			
		||||
                console.warn(`Unrecognized hash parameter '${name}'.`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        notePath,
 | 
			
		||||
        noteId: treeService.getNoteIdFromNotePath(notePath),
 | 
			
		||||
        ntxId,
 | 
			
		||||
        hoistedNoteId,
 | 
			
		||||
        viewScope
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function goToLink(evt) {
 | 
			
		||||
    const $link = $(evt.target).closest("a,.block-link");
 | 
			
		||||
    const hrefLink = $link.attr('href');
 | 
			
		||||
    const hrefLink = $link.attr('href') || $link.attr('data-href');
 | 
			
		||||
 | 
			
		||||
    if (hrefLink?.startsWith("data:")) {
 | 
			
		||||
        return true;
 | 
			
		||||
@ -139,7 +159,7 @@ function goToLink(evt) {
 | 
			
		||||
    evt.preventDefault();
 | 
			
		||||
    evt.stopPropagation();
 | 
			
		||||
 | 
			
		||||
    const { notePath, viewScope } = parseNotePathAndScope($link);
 | 
			
		||||
    const { notePath, viewScope } = parseNavigationStateFromUrl(hrefLink);
 | 
			
		||||
 | 
			
		||||
    const ctrlKey = utils.isCtrlKey(evt);
 | 
			
		||||
    const isLeftClick = evt.which === 1;
 | 
			
		||||
@ -186,8 +206,9 @@ function goToLink(evt) {
 | 
			
		||||
 | 
			
		||||
function linkContextMenu(e) {
 | 
			
		||||
    const $link = $(e.target).closest("a");
 | 
			
		||||
    const url = $link.attr("href") || $link.attr("data-href");
 | 
			
		||||
 | 
			
		||||
    const { notePath, viewScope } = parseNotePathAndScope($link);
 | 
			
		||||
    const { notePath, viewScope } = parseNavigationStateFromUrl(url);
 | 
			
		||||
 | 
			
		||||
    if (!notePath) {
 | 
			
		||||
        return;
 | 
			
		||||
@ -252,6 +273,6 @@ export default {
 | 
			
		||||
    createNoteLink,
 | 
			
		||||
    goToLink,
 | 
			
		||||
    loadReferenceLinkTitle,
 | 
			
		||||
    parseNotePathAndScope,
 | 
			
		||||
    calculateHash
 | 
			
		||||
    calculateHash,
 | 
			
		||||
    parseNavigationStateFromUrl
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -114,8 +114,7 @@ function initNoteAutocomplete($el, options) {
 | 
			
		||||
            .prop("title", "Show recent notes");
 | 
			
		||||
 | 
			
		||||
    const $goToSelectedNoteButton = $("<a>")
 | 
			
		||||
        .addClass("input-group-text go-to-selected-note-button bx bx-arrow-to-right")
 | 
			
		||||
        .attr("data-action", "note");
 | 
			
		||||
        .addClass("input-group-text go-to-selected-note-button bx bx-arrow-to-right");
 | 
			
		||||
 | 
			
		||||
    const $sideButtons = $("<div>")
 | 
			
		||||
        .addClass("input-group-append")
 | 
			
		||||
 | 
			
		||||
@ -54,9 +54,9 @@ async function getRenderedContent(note, options = {}) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (type === 'code') {
 | 
			
		||||
        const fullNote = await server.get(`notes/${note.noteId}`);
 | 
			
		||||
        const blob = await note.getBlob({ preview: options.trim });
 | 
			
		||||
 | 
			
		||||
        $renderedContent.append($("<pre>").text(trim(fullNote.content, options.trim)));
 | 
			
		||||
        $renderedContent.append($("<pre>").text(trim(blob.content, options.trim)));
 | 
			
		||||
    }
 | 
			
		||||
    else if (type === 'image') {
 | 
			
		||||
        const sanitizedTitle = note.title.replace(/[^a-z0-9-.]/gi, "");
 | 
			
		||||
 | 
			
		||||
@ -268,7 +268,7 @@ class NoteListRenderer {
 | 
			
		||||
 | 
			
		||||
        const {$renderedAttributes} = await attributeRenderer.renderNormalAttributes(note);
 | 
			
		||||
        const notePath = this.parentNote.type === 'search'
 | 
			
		||||
            ? note.noteId // for search note parent we want to display non-search path
 | 
			
		||||
            ? note.noteId // for search note parent, we want to display a non-search path
 | 
			
		||||
            : `${this.parentNote.noteId}/${note.noteId}`;
 | 
			
		||||
 | 
			
		||||
        const $card = $('<div class="note-book-card">')
 | 
			
		||||
@ -288,7 +288,7 @@ class NoteListRenderer {
 | 
			
		||||
        if (this.viewType === 'grid') {
 | 
			
		||||
            $card
 | 
			
		||||
                .addClass("block-link")
 | 
			
		||||
                .attr("data-note-path", notePath)
 | 
			
		||||
                .attr("data-href", `#${notePath}`)
 | 
			
		||||
                .on('click', e => linkService.goToLink(e));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,8 @@ async function mouseEnterHandler() {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const { notePath, noteId, viewScope } = linkService.parseNotePathAndScope($link);
 | 
			
		||||
    const url = $link.attr("href") || $link.attr("data-href");
 | 
			
		||||
    const { notePath, noteId, viewScope } = linkService.parseNavigationStateFromUrl(url);
 | 
			
		||||
 | 
			
		||||
    if (!notePath || viewScope.viewMode !== 'default') {
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -279,50 +279,6 @@ async function getNoteTitleWithPathAsSuffix(notePath) {
 | 
			
		||||
    return $titleWithPath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parseNavigationStateFromAddress() {
 | 
			
		||||
    const str = document.location.hash?.substr(1) || ""; // strip initial #
 | 
			
		||||
 | 
			
		||||
    const [notePath, paramString] = str.split("?");
 | 
			
		||||
    const viewScope = {
 | 
			
		||||
        viewMode: 'default'
 | 
			
		||||
    };
 | 
			
		||||
    let ntxId = null;
 | 
			
		||||
    let hoistedNoteId = null;
 | 
			
		||||
 | 
			
		||||
    if (paramString) {
 | 
			
		||||
        for (const pair of paramString.split("&")) {
 | 
			
		||||
            let [name, value] = pair.split("=");
 | 
			
		||||
            name = decodeURIComponent(name);
 | 
			
		||||
            value = decodeURIComponent(value);
 | 
			
		||||
 | 
			
		||||
            if (name === 'ntxId') {
 | 
			
		||||
                ntxId = value;
 | 
			
		||||
            } else if (name === 'hoistedNoteId') {
 | 
			
		||||
                hoistedNoteId = value;
 | 
			
		||||
            } else if (['viewMode', 'attachmentId'].includes(name)) {
 | 
			
		||||
                viewScope[name] = value;
 | 
			
		||||
            } else {
 | 
			
		||||
                console.warn(`Unrecognized hash parameter '${name}'.`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        notePath,
 | 
			
		||||
        ntxId,
 | 
			
		||||
        hoistedNoteId,
 | 
			
		||||
        viewScope
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isNotePathInAddress() {
 | 
			
		||||
    const {notePath, ntxId} = parseNavigationStateFromAddress();
 | 
			
		||||
 | 
			
		||||
    return notePath.startsWith("root")
 | 
			
		||||
        // empty string is for empty/uninitialized tab
 | 
			
		||||
        || (notePath === '' && !!ntxId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isNotePathInHiddenSubtree(notePath) {
 | 
			
		||||
    return notePath?.includes("root/_hidden");
 | 
			
		||||
}
 | 
			
		||||
@ -338,7 +294,5 @@ export default {
 | 
			
		||||
    getNoteTitle,
 | 
			
		||||
    getNotePathTitle,
 | 
			
		||||
    getNoteTitleWithPathAsSuffix,
 | 
			
		||||
    parseNavigationStateFromAddress,
 | 
			
		||||
    isNotePathInAddress,
 | 
			
		||||
    isNotePathInHiddenSubtree
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import BasicWidget from "./basic_widget.js";
 | 
			
		||||
import server from "../services/server.js";
 | 
			
		||||
import options from "../services/options.js";
 | 
			
		||||
import imageService from "../services/image.js";
 | 
			
		||||
import linkService from "../services/link.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="attachment-detail">
 | 
			
		||||
@ -15,6 +16,7 @@ const TPL = `
 | 
			
		||||
        .attachment-title-line {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: baseline;
 | 
			
		||||
            gap: 1em;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .attachment-details {
 | 
			
		||||
@ -54,10 +56,10 @@ const TPL = `
 | 
			
		||||
 | 
			
		||||
    <div class="attachment-detail-wrapper">
 | 
			
		||||
        <div class="attachment-title-line">
 | 
			
		||||
            <div class="attachment-actions-container"></div>
 | 
			
		||||
            <h4 class="attachment-title"></h4>                
 | 
			
		||||
            <div class="attachment-details"></div>
 | 
			
		||||
            <div style="flex: 1 1;"></div>
 | 
			
		||||
            <div class="attachment-actions-container"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div class="attachment-deletion-warning alert alert-info"></div>
 | 
			
		||||
@ -84,7 +86,7 @@ export default class AttachmentDetailWidget extends BasicWidget {
 | 
			
		||||
        super.doRender();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    refresh() {
 | 
			
		||||
    async refresh() {
 | 
			
		||||
        this.$widget.find('.attachment-detail-wrapper')
 | 
			
		||||
            .empty()
 | 
			
		||||
            .append(
 | 
			
		||||
@ -97,11 +99,13 @@ export default class AttachmentDetailWidget extends BasicWidget {
 | 
			
		||||
 | 
			
		||||
        if (!this.isFullDetail) {
 | 
			
		||||
            this.$wrapper.find('.attachment-title').append(
 | 
			
		||||
                $('<a href="javascript:">')
 | 
			
		||||
                    .attr("data-note-path", this.attachment.parentId)
 | 
			
		||||
                    .attr("data-view-mode", "attachments")
 | 
			
		||||
                    .attr("data-attachment-id", this.attachment.attachmentId)
 | 
			
		||||
                    .text(this.attachment.title)
 | 
			
		||||
                await linkService.createNoteLink(this.attachment.parentId, {
 | 
			
		||||
                    title: this.attachment.title,
 | 
			
		||||
                    viewScope: {
 | 
			
		||||
                        viewMode: 'attachments',
 | 
			
		||||
                        attachmentId: this.attachment.attachmentId
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            this.$wrapper.find('.attachment-title')
 | 
			
		||||
 | 
			
		||||
@ -701,9 +701,8 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
 | 
			
		||||
 | 
			
		||||
    createNoteLink(noteId) {
 | 
			
		||||
        return $("<a>", {
 | 
			
		||||
            href: `#${noteId}`,
 | 
			
		||||
            class: 'reference-link',
 | 
			
		||||
            'data-note-path': noteId
 | 
			
		||||
            href: `#root/${noteId}`,
 | 
			
		||||
            class: 'reference-link'
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -105,7 +105,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
 | 
			
		||||
 | 
			
		||||
        if (dateNoteId) {
 | 
			
		||||
            $newDay.addClass('calendar-date-exists');
 | 
			
		||||
            $newDay.attr("data-note-path", dateNoteId);
 | 
			
		||||
            $newDay.attr("href", `#root/dateNoteId`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.isEqual(this.date, this.activeDate)) {
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ export default class HistoryNavigationButton extends ButtonFromNoteWidget {
 | 
			
		||||
        for (const idx in this.webContents.history) {
 | 
			
		||||
            const url = this.webContents.history[idx];
 | 
			
		||||
            const [_, notePathWithTab] = url.split('#');
 | 
			
		||||
            // broken: use treeService.parseNavigationStateFromAddress();
 | 
			
		||||
            // broken: use linkService.parseNavigationStateFromUrl();
 | 
			
		||||
            const [notePath, ntxId] = notePathWithTab.split('-');
 | 
			
		||||
 | 
			
		||||
            const title = await treeService.getNotePathTitle(notePath);
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import TypeWidget from "./type_widget.js";
 | 
			
		||||
import server from "../../services/server.js";
 | 
			
		||||
import AttachmentDetailWidget from "../attachment_detail.js";
 | 
			
		||||
import linkService from "../../services/link.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="attachment-detail note-detail-printable">
 | 
			
		||||
@ -10,6 +11,8 @@ const TPL = `
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <div class="links-wrapper"></div>
 | 
			
		||||
 | 
			
		||||
    <div class="attachment-wrapper"></div>
 | 
			
		||||
</div>`;
 | 
			
		||||
 | 
			
		||||
@ -29,6 +32,8 @@ export default class AttachmentDetailTypeWidget extends TypeWidget {
 | 
			
		||||
        this.$wrapper.empty();
 | 
			
		||||
        this.children = [];
 | 
			
		||||
 | 
			
		||||
        linkService.createNoteLink(this.noteId, {});
 | 
			
		||||
 | 
			
		||||
        const attachment = await server.get(`attachments/${this.attachmentId}/?includeContent=true`);
 | 
			
		||||
 | 
			
		||||
        if (!attachment) {
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ function sanitize(dirtyHtml) {
 | 
			
		||||
            'en-media' // for ENEX import
 | 
			
		||||
        ],
 | 
			
		||||
        allowedAttributes: {
 | 
			
		||||
            'a': [ 'href', 'class', 'data-note-path' ],
 | 
			
		||||
            'a': [ 'href', 'class' ],
 | 
			
		||||
            'img': [ 'src' ],
 | 
			
		||||
            'section': [ 'class', 'data-note-id' ],
 | 
			
		||||
            'figure': [ 'class' ],
 | 
			
		||||
 | 
			
		||||
@ -376,20 +376,6 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
 | 
			
		||||
            return `href="#root/${target.noteId}"`;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        content = content.replace(/data-note-path="([^"]*)"/g, (match, notePath) => {
 | 
			
		||||
            const noteId = notePath.split("/").pop();
 | 
			
		||||
 | 
			
		||||
            let targetNoteId;
 | 
			
		||||
 | 
			
		||||
            if (noteId === 'root' || noteId.startsWith("_")) { // named noteIds stay identical across instances
 | 
			
		||||
                targetNoteId = noteId;
 | 
			
		||||
            } else {
 | 
			
		||||
                targetNoteId = noteIdMap[noteId];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return `data-note-path="root/${targetNoteId}"`;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (noteMeta) {
 | 
			
		||||
            const includeNoteLinks = (noteMeta.attributes || [])
 | 
			
		||||
                .filter(attr => attr.type === 'relation' && attr.name === 'includeNoteLink');
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user