backlinks improvements, #2349

This commit is contained in:
zadam 2021-12-02 22:00:42 +01:00
parent bbceb6251a
commit 630d9f2e45
6 changed files with 122 additions and 100 deletions

View File

@ -2,7 +2,7 @@ image:
file: .gitpod.dockerfile file: .gitpod.dockerfile
tasks: 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 init: npm install
command: npm run start-server command: npm run start-server

View File

@ -1,4 +1,4 @@
FROM node:16.13.0-alpine FROM node:16.13.1-alpine
# Create app directory # Create app directory
WORKDIR /usr/src/app WORKDIR /usr/src/app

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
PKG_DIR=dist/trilium-linux-x64-server PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=16.13.0 NODE_VERSION=16.13.1
if [ "$1" != "DONTCOPY" ] if [ "$1" != "DONTCOPY" ]
then then

View File

@ -5,7 +5,7 @@ if [[ $# -eq 0 ]] ; then
exit 1 exit 1
fi fi
n exec 16.13.0 npm run webpack n exec 16.13.1 npm run webpack
DIR=$1 DIR=$1
@ -27,7 +27,7 @@ cp -r electron.js $DIR/
cp webpack-* $DIR/ cp webpack-* $DIR/
# run in subshell (so we return to original 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 # cleanup of useless files in dependencies
rm -r $DIR/node_modules/image-q/demo rm -r $DIR/node_modules/image-q/demo

View File

@ -23,6 +23,7 @@ const TPL = `
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
z-index: 10;
} }
.backlinks-count { .backlinks-count {
@ -56,6 +57,15 @@ const TPL = `
opacity: 80%; opacity: 80%;
font-size: 90%; 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; }
</style> </style>
<div class="backlinks-ticker"> <div class="backlinks-ticker">
@ -136,8 +146,12 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
showTooltip: false showTooltip: false
})); }));
this.$items.append("<br/>"); if (backlink.relationName) {
this.$items.append($("<p>").text("relation: " + backlink.relationName));
}
else {
this.$items.append(...backlink.excerpts); this.$items.append(...backlink.excerpts);
} }
} }
}
} }

View File

@ -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) { function getBacklinks(req) {
const {noteId} = req.params; const {noteId} = req.params;
const note = becca.getNote(noteId); const note = becca.getNote(noteId);
@ -192,104 +283,21 @@ function getBacklinks(req) {
let backlinks = note.getTargetRelations(); let backlinks = note.getTargetRelations();
if (backlinks.length > 50) { let backlinksWithExcerptCount = 0;
backlinks = backlinks.slice(0, 50);
}
return backlinks.map(backlink => { return backlinks.map(backlink => {
const sourceNote = backlink.note; const sourceNote = backlink.note;
const html = sourceNote.getContent(); if (sourceNote.type !== 'text' || backlinksWithExcerptCount > 50) {
const dom = new JSDOM(html); return {
noteId: sourceNote.noteId,
const excerpts = []; relationName: backlink.name
};
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"; backlinksWithExcerptCount++;
linkEl.style.backgroundColor = "yellow";
const LIMIT = 200; const excerpts = findExcerpts(sourceNote, noteId);
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);
}
return { return {
noteId: sourceNote.noteId, noteId: sourceNote.noteId,