diff --git a/.gitpod.yml b/.gitpod.yml index 40dcc1b95..a7f713d3a 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -2,7 +2,7 @@ image: file: .gitpod.dockerfile tasks: - - before: nvm install 16.13.0 && nvm use 16.13.0 + - before: nvm install 16.13.1 && nvm use 16.13.1 init: npm install command: npm run start-server diff --git a/Dockerfile b/Dockerfile index 0258e6c6d..b1ebbe7ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.13.0-alpine +FROM node:16.13.1-alpine # Create app directory WORKDIR /usr/src/app diff --git a/bin/build-server.sh b/bin/build-server.sh index 437c87c5a..805c2234f 100755 --- a/bin/build-server.sh +++ b/bin/build-server.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash PKG_DIR=dist/trilium-linux-x64-server -NODE_VERSION=16.13.0 +NODE_VERSION=16.13.1 if [ "$1" != "DONTCOPY" ] then diff --git a/bin/copy-trilium.sh b/bin/copy-trilium.sh index 975917b35..c9439f79b 100755 --- a/bin/copy-trilium.sh +++ b/bin/copy-trilium.sh @@ -5,7 +5,7 @@ if [[ $# -eq 0 ]] ; then exit 1 fi -n exec 16.13.0 npm run webpack +n exec 16.13.1 npm run webpack DIR=$1 @@ -27,7 +27,7 @@ cp -r electron.js $DIR/ cp webpack-* $DIR/ # run in subshell (so we return to original dir) -(cd $DIR && n exec 16.13.0 npm install --only=prod) +(cd $DIR && n exec 16.13.1 npm install --only=prod) # cleanup of useless files in dependencies rm -r $DIR/node_modules/image-q/demo diff --git a/src/public/app/widgets/backlinks.js b/src/public/app/widgets/backlinks.js index 2b1353b6a..8ed93d9cf 100644 --- a/src/public/app/widgets/backlinks.js +++ b/src/public/app/widgets/backlinks.js @@ -23,6 +23,7 @@ const TPL = ` display: flex; justify-content: space-between; align-items: center; + z-index: 10; } .backlinks-count { @@ -56,6 +57,15 @@ const TPL = ` opacity: 80%; font-size: 90%; } + + .backlink-excerpt .backlink-link { /* the actual backlink */ + font-weight: bold; + background-color: yellow; + } + + /* relation map has already buttons in that position */ + .type-relation-map .backlinks-ticker { top: 50px; } + .type-relation-map .backlinks-items { top: 100px; }
").text("relation: " + backlink.relationName)); + } + else { + this.$items.append(...backlink.excerpts); + } } } } diff --git a/src/routes/api/note_map.js b/src/routes/api/note_map.js index 5e14a7140..dc9a99b8d 100644 --- a/src/routes/api/note_map.js +++ b/src/routes/api/note_map.js @@ -182,6 +182,97 @@ function removeImages(document) { } } +const EXCERPT_CHAR_LIMIT = 200; + +function findExcerpts(sourceNote, referencedNoteId) { + const html = sourceNote.getContent(); + const document = new JSDOM(html).window.document; + + const excerpts = []; + + removeImages(document); + + for (const linkEl of document.querySelectorAll("a")) { + const href = linkEl.getAttribute("href"); + + if (!href || !href.endsWith(referencedNoteId)) { + continue; + } + + linkEl.classList.add("backlink-link"); + + let centerEl = linkEl; + + while (centerEl.tagName !== 'BODY' && centerEl.parentElement.textContent.length <= EXCERPT_CHAR_LIMIT) { + centerEl = centerEl.parentElement; + } + + const excerptEls = [centerEl]; + let excerptLength = centerEl.textContent.length; + let left = centerEl; + let right = centerEl; + + while (excerptLength < EXCERPT_CHAR_LIMIT) { + let added = false; + + const prev = left.previousElementSibling; + + if (prev) { + const prevText = prev.textContent; + + if (prevText.length + excerptLength > EXCERPT_CHAR_LIMIT) { + const prefix = prevText.substr(prevText.length - (EXCERPT_CHAR_LIMIT - excerptLength)); + + const textNode = document.createTextNode("…" + prefix); + excerptEls.unshift(textNode); + + break; + } + + left = prev; + excerptEls.unshift(left); + excerptLength += prevText.length; + added = true; + } + + const next = right.nextElementSibling; + + if (next) { + const nextText = next.textContent; + + if (nextText.length + excerptLength > EXCERPT_CHAR_LIMIT) { + const suffix = nextText.substr(nextText.length - (EXCERPT_CHAR_LIMIT - excerptLength)); + + const textNode = document.createTextNode(suffix + "…"); + excerptEls.push(textNode); + + break; + } + + right = next; + excerptEls.push(right); + excerptLength += nextText.length; + added = true; + } + + if (!added) { + break; + } + } + + const excerptWrapper = document.createElement('div'); + excerptWrapper.classList.add("ck-content"); + excerptWrapper.classList.add("backlink-excerpt"); + + for (const childEl of excerptEls) { + excerptWrapper.appendChild(childEl); + } + + excerpts.push(excerptWrapper.outerHTML); + } + return excerpts; +} + function getBacklinks(req) { const {noteId} = req.params; const note = becca.getNote(noteId); @@ -192,105 +283,22 @@ function getBacklinks(req) { let backlinks = note.getTargetRelations(); - if (backlinks.length > 50) { - backlinks = backlinks.slice(0, 50); - } + let backlinksWithExcerptCount = 0; return backlinks.map(backlink => { const sourceNote = backlink.note; - const html = sourceNote.getContent(); - const dom = new JSDOM(html); - - const excerpts = []; - - const document = dom.window.document; - - removeImages(document); - - for (const linkEl of document.querySelectorAll("a")) { - const href = linkEl.getAttribute("href"); - - if (!href || !href.includes(noteId)) { - continue; - } - - linkEl.style.fontWeight = "bold"; - linkEl.style.backgroundColor = "yellow"; - - const LIMIT = 200; - let centerEl = linkEl; - - while (centerEl.tagName !== 'BODY' && centerEl.parentElement.textContent.length < LIMIT) { - centerEl = centerEl.parentElement; - } - - const sub = [centerEl]; - let counter = centerEl.textContent.length; - let left = centerEl; - let right = centerEl; - - while (true) { - let added = false; - - const prev = left.previousElementSibling; - - if (prev) { - const prevText = prev.textContent; - - if (prevText.length + counter > LIMIT) { - const prefix = prevText.substr(prevText.length - (LIMIT - counter)); - - const textNode = document.createTextNode("…" + prefix); - sub.unshift(textNode); - - break; - } - - left = prev; - sub.unshift(left); - counter += prevText.length; - added = true; - } - - const next = right.nextElementSibling; - - if (next) { - const nextText = next.textContent; - - if (nextText.length + counter > LIMIT) { - const suffix = nextText.substr(nextText.length - (LIMIT - counter)); - - const textNode = document.createTextNode(suffix + "…"); - sub.push(textNode); - - break; - } - - right = next; - sub.push(right); - counter += nextText.length; - added = true; - } - - if (!added) { - break; - } - } - - const div = document.createElement('div'); - div.classList.add("ck-content"); - div.classList.add("backlink-excerpt"); - - for (const childEl of sub) { - div.appendChild(childEl); - } - - const subHtml = div.outerHTML; - - excerpts.push(subHtml); + if (sourceNote.type !== 'text' || backlinksWithExcerptCount > 50) { + return { + noteId: sourceNote.noteId, + relationName: backlink.name + }; } + backlinksWithExcerptCount++; + + const excerpts = findExcerpts(sourceNote, noteId); + return { noteId: sourceNote.noteId, excerpts