mirror of
https://github.com/zadam/trilium.git
synced 2026-05-07 03:16:35 +02:00
fix(anchors): detection no longer working
This commit is contained in:
@@ -14,6 +14,25 @@ import { useTriliumEvent } from "../react/hooks";
|
||||
|
||||
type LinkType = "reference-link" | "external-link" | "hyper-link";
|
||||
|
||||
function findAnchorIds(content: string): string[] {
|
||||
const re = /<a\b([^>]*)>(<\/a>)?/g;
|
||||
const ids: string[] = [];
|
||||
let match;
|
||||
|
||||
while ((match = re.exec(content))) {
|
||||
const attrs = match[1];
|
||||
if (/\bhref\s*=/.test(attrs)) continue;
|
||||
|
||||
const idMatch = /\bid\s*=\s*"([^"]+)"/.exec(attrs) ?? /\bid\s*=\s*'([^']+)'/.exec(attrs);
|
||||
if (!idMatch) continue;
|
||||
|
||||
const id = idMatch[1];
|
||||
if (!ids.includes(id)) ids.push(id);
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
export interface AddLinkOpts {
|
||||
text: string;
|
||||
hasSelection: boolean;
|
||||
@@ -67,12 +86,25 @@ export default function AddLinkDialog() {
|
||||
const noteId = tree.getNoteIdFromUrl(suggestion.notePath);
|
||||
if (noteId) {
|
||||
setDefaultLinkTitle(noteId);
|
||||
froca.getNote(noteId).then((note) => {
|
||||
if (cancelled) return;
|
||||
const bkms = note?.getLabels("internalBookmark").map((l) => l.value) ?? [];
|
||||
(async () => {
|
||||
const note = await froca.getNote(noteId);
|
||||
if (cancelled || !note) return;
|
||||
|
||||
let bkms = note.getLabels("internalBookmark").map((l) => l.value);
|
||||
|
||||
// Fall back to scanning the note content for anchors if no labels
|
||||
// are present (e.g. notes that predate the bookmark-label feature).
|
||||
if (bkms.length === 0 && note.type === "text") {
|
||||
const content = await note.getContent();
|
||||
if (cancelled) return;
|
||||
if (typeof content === "string") {
|
||||
bkms = findAnchorIds(content);
|
||||
}
|
||||
}
|
||||
|
||||
setBookmarks(bkms);
|
||||
setSelectedBookmark("");
|
||||
});
|
||||
})();
|
||||
}
|
||||
resetExternalLink();
|
||||
}
|
||||
|
||||
@@ -279,8 +279,10 @@ export default class Becca {
|
||||
*/
|
||||
getFlatTextIndex(): { notes: BNote[], flatTexts: string[], noteIdToIdx: Map<string, number> } {
|
||||
if (!this.flatTextIndex) {
|
||||
// Measure heap before building
|
||||
const heapBefore = process.memoryUsage().heapUsed;
|
||||
// Measure heap before building (only available under Node.js)
|
||||
const heapBefore = typeof process !== "undefined" && typeof process.memoryUsage === "function"
|
||||
? process.memoryUsage().heapUsed
|
||||
: null;
|
||||
|
||||
const allNoteSet = this.getAllNoteSet();
|
||||
const notes: BNote[] = [];
|
||||
@@ -296,10 +298,12 @@ export default class Becca {
|
||||
this.flatTextIndex = { notes, flatTexts, noteIdToIdx };
|
||||
this.dirtyFlatTextNoteIds.clear();
|
||||
|
||||
// Measure heap after building and log
|
||||
const heapAfter = process.memoryUsage().heapUsed;
|
||||
const heapDelta = heapAfter - heapBefore;
|
||||
getLog().info(`Flat text search index built: ${notes.length} notes, ${formatSize(heapDelta)}`);
|
||||
if (heapBefore !== null) {
|
||||
const heapDelta = process.memoryUsage().heapUsed - heapBefore;
|
||||
getLog().info(`Flat text search index built: ${notes.length} notes, ${formatSize(heapDelta)}`);
|
||||
} else {
|
||||
getLog().info(`Flat text search index built: ${notes.length} notes`);
|
||||
}
|
||||
} else if (this.dirtyFlatTextNoteIds.size > 0) {
|
||||
// Incremental update: only recompute flat texts for dirtied notes
|
||||
const { flatTexts, noteIdToIdx } = this.flatTextIndex;
|
||||
|
||||
@@ -118,7 +118,15 @@ class BAttribute extends AbstractBeccaEntity<BAttribute> {
|
||||
}
|
||||
|
||||
isAutoLink() {
|
||||
return this.type === "relation" && ["internalLink", "imageLink", "relationMapLink", "includeNoteLink"].includes(this.name);
|
||||
if (this.type === "relation") {
|
||||
return ["internalLink", "imageLink", "relationMapLink", "includeNoteLink"].includes(this.name);
|
||||
}
|
||||
|
||||
if (this.type === "label") {
|
||||
return this.name === "internalBookmark";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get note() {
|
||||
|
||||
@@ -515,19 +515,27 @@ function findIncludeNoteLinks(content: string, foundLinks: FoundLink[]) {
|
||||
/**
|
||||
* Extracts bookmark IDs from CKEditor bookmark anchors (`<a id="..."></a>` without href).
|
||||
* Bookmarks are stored as labels on the note so they can be looked up without parsing content.
|
||||
* Matches id regardless of attribute order; skips anchors with href (those are regular links).
|
||||
*/
|
||||
export function findBookmarks(content: string): string[] {
|
||||
const re = /<a\s+id="([^"]+)"[^>]*>(<\/a>)?/g;
|
||||
const re = /<a\b([^>]*)>(<\/a>)?/g;
|
||||
const bookmarks: string[] = [];
|
||||
let match;
|
||||
|
||||
while ((match = re.exec(content))) {
|
||||
const attrs = match[1];
|
||||
|
||||
// Skip anchors that also have an href (those are regular links, not bookmarks)
|
||||
if (match[0].includes("href=")) {
|
||||
if (/\bhref\s*=/.test(attrs)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const id = match[1];
|
||||
const idMatch = /\bid\s*=\s*"([^"]+)"/.exec(attrs) ?? /\bid\s*=\s*'([^']+)'/.exec(attrs);
|
||||
if (!idMatch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const id = idMatch[1];
|
||||
if (!bookmarks.includes(id)) {
|
||||
bookmarks.push(id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user