mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
server-ts: Convert routes/api/note_map
This commit is contained in:
parent
b1744c3867
commit
37697c7db7
@ -1,18 +1,25 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
const { JSDOM } = require("jsdom");
|
import { JSDOM } from "jsdom";
|
||||||
|
import BNote = require('../../becca/entities/bnote');
|
||||||
|
import BAttribute = require('../../becca/entities/battribute');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
|
||||||
function buildDescendantCountMap(noteIdsToCount) {
|
function buildDescendantCountMap(noteIdsToCount: string[]) {
|
||||||
if (!Array.isArray(noteIdsToCount)) {
|
if (!Array.isArray(noteIdsToCount)) {
|
||||||
throw new Error('noteIdsToCount: type error');
|
throw new Error('noteIdsToCount: type error');
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteIdToCountMap = Object.create(null);
|
const noteIdToCountMap = Object.create(null);
|
||||||
|
|
||||||
function getCount(noteId) {
|
function getCount(noteId: string) {
|
||||||
if (!(noteId in noteIdToCountMap)) {
|
if (!(noteId in noteIdToCountMap)) {
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNote(noteId);
|
||||||
|
if (!note) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const hiddenImageNoteIds = note.getRelations('imageLink').map(rel => rel.value);
|
const hiddenImageNoteIds = note.getRelations('imageLink').map(rel => rel.value);
|
||||||
const childNoteIds = note.children.map(child => child.noteId);
|
const childNoteIds = note.children.map(child => child.noteId);
|
||||||
@ -33,19 +40,14 @@ function buildDescendantCountMap(noteIdsToCount) {
|
|||||||
|
|
||||||
return noteIdToCountMap;
|
return noteIdToCountMap;
|
||||||
}
|
}
|
||||||
/**
|
function getNeighbors(note: BNote, depth: number): string[] {
|
||||||
* @param {BNote} note
|
|
||||||
* @param {int} depth
|
|
||||||
* @returns {string[]} noteIds
|
|
||||||
*/
|
|
||||||
function getNeighbors(note, depth) {
|
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const retNoteIds = [];
|
const retNoteIds = [];
|
||||||
|
|
||||||
function isIgnoredRelation(relation) {
|
function isIgnoredRelation(relation: BAttribute) {
|
||||||
return ['relationMapLink', 'template', 'inherit', 'image', 'ancestor'].includes(relation.name);
|
return ['relationMapLink', 'template', 'inherit', 'image', 'ancestor'].includes(relation.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +92,9 @@ function getNeighbors(note, depth) {
|
|||||||
return retNoteIds;
|
return retNoteIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLinkMap(req) {
|
function getLinkMap(req: Request) {
|
||||||
const mapRootNote = becca.getNote(req.params.noteId);
|
const mapRootNote = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
// if the map root itself has "excludeFromNoteMap" attribute (journal typically) then there wouldn't be anything
|
// if the map root itself has "excludeFromNoteMap" attribute (journal typically) then there wouldn't be anything
|
||||||
// to display, so we'll just ignore it
|
// to display, so we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
||||||
@ -125,7 +128,7 @@ function getLinkMap(req) {
|
|||||||
const noteIdsArray = Array.from(noteIds)
|
const noteIdsArray = Array.from(noteIds)
|
||||||
|
|
||||||
const notes = noteIdsArray.map(noteId => {
|
const notes = noteIdsArray.map(noteId => {
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
note.noteId,
|
note.noteId,
|
||||||
@ -144,6 +147,9 @@ function getLinkMap(req) {
|
|||||||
}
|
}
|
||||||
else if (rel.name === 'imageLink') {
|
else if (rel.name === 'imageLink') {
|
||||||
const parentNote = becca.getNote(rel.noteId);
|
const parentNote = becca.getNote(rel.noteId);
|
||||||
|
if (!parentNote) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return !parentNote.getChildNotes().find(childNote => childNote.noteId === rel.value);
|
return !parentNote.getChildNotes().find(childNote => childNote.noteId === rel.value);
|
||||||
}
|
}
|
||||||
@ -165,8 +171,8 @@ function getLinkMap(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTreeMap(req) {
|
function getTreeMap(req: Request) {
|
||||||
const mapRootNote = becca.getNote(req.params.noteId);
|
const mapRootNote = becca.getNoteOrThrow(req.params.noteId);
|
||||||
// if the map root itself has "excludeFromNoteMap" (journal typically) then there wouldn't be anything to display,
|
// if the map root itself has "excludeFromNoteMap" (journal typically) then there wouldn't be anything to display,
|
||||||
// so we'll just ignore it
|
// so we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
||||||
@ -198,8 +204,8 @@ function getTreeMap(req) {
|
|||||||
note.getLabelValue('color')
|
note.getLabelValue('color')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const noteIds = new Set();
|
const noteIds = new Set<string>();
|
||||||
notes.forEach(([noteId]) => noteIds.add(noteId));
|
notes.forEach(([noteId]) => noteId && noteIds.add(noteId));
|
||||||
|
|
||||||
const links = [];
|
const links = [];
|
||||||
|
|
||||||
@ -225,7 +231,7 @@ function getTreeMap(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDescendantCountMapForSearch(noteIdToDescendantCountMap, relationships) {
|
function updateDescendantCountMapForSearch(noteIdToDescendantCountMap: Record<string, number>, relationships: { parentNoteId: string, childNoteId: string }[]) {
|
||||||
for (const {parentNoteId, childNoteId} of relationships) {
|
for (const {parentNoteId, childNoteId} of relationships) {
|
||||||
const parentNote = becca.notes[parentNoteId];
|
const parentNote = becca.notes[parentNoteId];
|
||||||
if (!parentNote || parentNote.type !== 'search') {
|
if (!parentNote || parentNote.type !== 'search') {
|
||||||
@ -237,16 +243,17 @@ function updateDescendantCountMapForSearch(noteIdToDescendantCountMap, relations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeImages(document) {
|
function removeImages(document: Document) {
|
||||||
const images = document.getElementsByTagName('img');
|
const images = document.getElementsByTagName('img');
|
||||||
while (images.length > 0) {
|
while (images && images.length > 0) {
|
||||||
images[0].parentNode.removeChild(images[0]);
|
images[0]?.parentNode?.removeChild(images[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXCERPT_CHAR_LIMIT = 200;
|
const EXCERPT_CHAR_LIMIT = 200;
|
||||||
|
type ElementOrText = (Element | Text);
|
||||||
|
|
||||||
function findExcerpts(sourceNote, referencedNoteId) {
|
function findExcerpts(sourceNote: BNote, referencedNoteId: string) {
|
||||||
const html = sourceNote.getContent();
|
const html = sourceNote.getContent();
|
||||||
const document = new JSDOM(html).window.document;
|
const document = new JSDOM(html).window.document;
|
||||||
|
|
||||||
@ -263,25 +270,24 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
|
|
||||||
linkEl.classList.add("backlink-link");
|
linkEl.classList.add("backlink-link");
|
||||||
|
|
||||||
let centerEl = linkEl;
|
let centerEl: HTMLElement = linkEl;
|
||||||
|
|
||||||
while (centerEl.tagName !== 'BODY' && centerEl.parentElement?.textContent?.length <= EXCERPT_CHAR_LIMIT) {
|
while (centerEl.tagName !== 'BODY' && centerEl.parentElement && (centerEl.parentElement?.textContent?.length || 0) <= EXCERPT_CHAR_LIMIT) {
|
||||||
centerEl = centerEl.parentElement;
|
centerEl = centerEl.parentElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var {HTMLElement[]} */
|
const excerptEls: ElementOrText[] = [centerEl];
|
||||||
const excerptEls = [centerEl];
|
let excerptLength = centerEl.textContent?.length || 0;
|
||||||
let excerptLength = centerEl.textContent.length;
|
let left: ElementOrText = centerEl;
|
||||||
let left = centerEl;
|
let right: ElementOrText = centerEl;
|
||||||
let right = centerEl;
|
|
||||||
|
|
||||||
while (excerptLength < EXCERPT_CHAR_LIMIT) {
|
while (excerptLength < EXCERPT_CHAR_LIMIT) {
|
||||||
let added = false;
|
let added = false;
|
||||||
|
|
||||||
const prev = left.previousElementSibling;
|
const prev: Element | null = left.previousElementSibling;
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
const prevText = prev.textContent;
|
const prevText = prev.textContent || "";
|
||||||
|
|
||||||
if (prevText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
if (prevText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
||||||
const prefix = prevText.substr(prevText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
const prefix = prevText.substr(prevText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
||||||
@ -298,12 +304,12 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const next = right.nextElementSibling;
|
const next: Element | null = right.nextElementSibling;
|
||||||
|
|
||||||
if (next) {
|
if (next) {
|
||||||
const nextText = next.textContent;
|
const nextText = next.textContent;
|
||||||
|
|
||||||
if (nextText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
if (nextText && nextText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
||||||
const suffix = nextText.substr(nextText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
const suffix = nextText.substr(nextText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
||||||
|
|
||||||
const textNode = document.createTextNode(`${suffix}…`);
|
const textNode = document.createTextNode(`${suffix}…`);
|
||||||
@ -314,7 +320,7 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
|
|
||||||
right = next;
|
right = next;
|
||||||
excerptEls.push(right);
|
excerptEls.push(right);
|
||||||
excerptLength += nextText.length;
|
excerptLength += nextText?.length || 0;
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,13 +342,13 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
return excerpts;
|
return excerpts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFilteredBacklinks(note) {
|
function getFilteredBacklinks(note: BNote) {
|
||||||
return note.getTargetRelations()
|
return note.getTargetRelations()
|
||||||
// search notes have "ancestor" relations which are not interesting
|
// search notes have "ancestor" relations which are not interesting
|
||||||
.filter(relation => !!relation.getNote() && relation.getNote().type !== 'search');
|
.filter(relation => !!relation.getNote() && relation.getNote().type !== 'search');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBacklinkCount(req) {
|
function getBacklinkCount(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
|
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
@ -352,7 +358,7 @@ function getBacklinkCount(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBacklinks(req) {
|
function getBacklinks(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
@ -379,7 +385,7 @@ function getBacklinks(req) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getLinkMap,
|
getLinkMap,
|
||||||
getTreeMap,
|
getTreeMap,
|
||||||
getBacklinkCount,
|
getBacklinkCount,
|
@ -49,7 +49,7 @@ const filesRoute = require('./api/files');
|
|||||||
const searchRoute = require('./api/search');
|
const searchRoute = require('./api/search');
|
||||||
const bulkActionRoute = require('./api/bulk_action');
|
const bulkActionRoute = require('./api/bulk_action');
|
||||||
const specialNotesRoute = require('./api/special_notes');
|
const specialNotesRoute = require('./api/special_notes');
|
||||||
const noteMapRoute = require('./api/note_map.js');
|
const noteMapRoute = require('./api/note_map');
|
||||||
const clipperRoute = require('./api/clipper');
|
const clipperRoute = require('./api/clipper');
|
||||||
const similarNotesRoute = require('./api/similar_notes.js');
|
const similarNotesRoute = require('./api/similar_notes.js');
|
||||||
const keysRoute = require('./api/keys');
|
const keysRoute = require('./api/keys');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user