mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	small refactorings and fixes
This commit is contained in:
		| @@ -5,7 +5,8 @@ const NoteSet = require("../services/search/note_set"); | ||||
| const NotFoundError = require("../errors/not_found_error"); | ||||
|  | ||||
| /** | ||||
|  * Becca is a backend cache of all notes, branches and attributes. There's a similar frontend cache Froca. | ||||
|  * Becca is a backend cache of all notes, branches, and attributes. | ||||
|  * There's a similar frontend cache Froca, and share cache Shaca. | ||||
|  */ | ||||
| class Becca { | ||||
|     constructor() { | ||||
|   | ||||
| @@ -28,7 +28,7 @@ function load() { | ||||
|     becca.reset(); | ||||
|  | ||||
|     // using a raw query and passing arrays to avoid allocating new objects, | ||||
|     // this is worth it for becca load since it happens every run and blocks the app until finished | ||||
|     // this is worth it for the becca load since it happens every run and blocks the app until finished | ||||
|  | ||||
|     for (const row of sql.getRawRows(`SELECT noteId, title, type, mime, isProtected, blobId, dateCreated, dateModified, utcDateCreated, utcDateModified FROM notes WHERE isDeleted = 0`)) { | ||||
|         new BNote().update(row).init(); | ||||
|   | ||||
| @@ -46,7 +46,7 @@ class BAttachment extends AbstractBeccaEntity { | ||||
|         this.mime = row.mime; | ||||
|         /** @type {string} */ | ||||
|         this.title = row.title; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.position = row.position; | ||||
|         /** @type {string} */ | ||||
|         this.blobId = row.blobId; | ||||
| @@ -59,7 +59,7 @@ class BAttachment extends AbstractBeccaEntity { | ||||
|         /** @type {string} */ | ||||
|         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||
|  | ||||
|         /** @type {integer} optionally added to the entity */ | ||||
|         /** @type {int} optionally added to the entity */ | ||||
|         this.contentLength = row.contentLength; | ||||
|  | ||||
|         this.decrypt(); | ||||
|   | ||||
| @@ -51,7 +51,7 @@ class BAttribute extends AbstractBeccaEntity { | ||||
|         this.type = type; | ||||
|         /** @type {string} */ | ||||
|         this.name = name; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.position = position; | ||||
|         /** @type {string} */ | ||||
|         this.value = value || ""; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ class BBlob { | ||||
|         this.blobId = row.blobId; | ||||
|         /** @type {string|Buffer} */ | ||||
|         this.content = row.content; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.contentLength = row.contentLength; | ||||
|         /** @type {string} */ | ||||
|         this.dateModified = row.dateModified; | ||||
|   | ||||
| @@ -55,7 +55,7 @@ class BBranch extends AbstractBeccaEntity { | ||||
|         this.parentNoteId = parentNoteId; | ||||
|         /** @type {string|null} */ | ||||
|         this.prefix = prefix; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.notePosition = notePosition; | ||||
|         /** @type {boolean} */ | ||||
|         this.isExpanded = !!isExpanded; | ||||
|   | ||||
| @@ -47,7 +47,7 @@ class BRevision extends AbstractBeccaEntity { | ||||
|         this.utcDateCreated = row.utcDateCreated; | ||||
|         /** @type {string} */ | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.contentLength = row.contentLength; | ||||
|  | ||||
|         if (this.isProtected && !titleDecrypted) { | ||||
|   | ||||
| @@ -134,7 +134,7 @@ function buildRewardMap(note) { | ||||
|  | ||||
|         // title is the top with weight 1 so smaller headings will have lower weight | ||||
|  | ||||
|         // technically H1 is not supported but for the case it's present let's weigh it just as H2 | ||||
|         // technically H1 is not supported, but for the case it's present let's weigh it just as H2 | ||||
|         addHeadingsToRewardMap("h1", 0.9); | ||||
|         addHeadingsToRewardMap("h2", 0.9); | ||||
|         addHeadingsToRewardMap("h3", 0.8); | ||||
| @@ -447,7 +447,7 @@ async function findSimilarNotes(noteId) { | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Point of this is to break up long-running sync process to avoid blocking | ||||
|  * The point of this is to break up the long-running sync process to avoid blocking | ||||
|  * see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/ | ||||
|  */ | ||||
| function setImmediatePromise() { | ||||
|   | ||||
| @@ -63,7 +63,7 @@ function register(router) { | ||||
|             throw new eu.EtapiError(400, "ATTACHMENT_IS_PROTECTED", `Attachment '${req.params.attachmentId}' is protected and content cannot be read through ETAPI.`); | ||||
|         } | ||||
|  | ||||
|         const filename = utils.formatDownloadTitle(attachment.title, attachment.type, attachment.mime); | ||||
|         const filename = utils.formatDownloadTitle(attachment.title, attachment.role, attachment.mime); | ||||
|  | ||||
|         res.setHeader('Content-Disposition', utils.getContentDisposition(filename)); | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import options from "../services/options.js"; | ||||
| import utils from "../services/utils.js"; | ||||
| import zoomComponent from "./zoom.js"; | ||||
| 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"; | ||||
|   | ||||
| @@ -23,7 +23,7 @@ class FAttachment { | ||||
|         /** @type {string} */ | ||||
|         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||
|  | ||||
|         /** @type {integer} optionally added to the entity */ | ||||
|         /** @type {int} optionally added to the entity */ | ||||
|         this.contentLength = row.contentLength; | ||||
|  | ||||
|         this.froca.attachments[this.attachmentId] = this; | ||||
|   | ||||
| @@ -22,7 +22,7 @@ class FAttribute { | ||||
|         this.name = row.name; | ||||
|         /** @type {string} */ | ||||
|         this.value = row.value; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.position = row.position; | ||||
|         /** @type {boolean} */ | ||||
|         this.isInheritable = !!row.isInheritable; | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class FBranch { | ||||
|         this.noteId = row.noteId; | ||||
|         /** @type {string} */ | ||||
|         this.parentNoteId = row.parentNoteId; | ||||
|         /** @type {integer} */ | ||||
|         /** @type {int} */ | ||||
|         this.notePosition = row.notePosition; | ||||
|         /** @type {string} */ | ||||
|         this.prefix = row.prefix; | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ws from "../services/ws.js"; | ||||
| import froca from "../services/froca.js"; | ||||
| import protectedSessionHolder from "../services/protected_session_holder.js"; | ||||
| import cssClassManager from "../services/css_class_manager.js"; | ||||
| import FAttachment from "./fattachment.js"; | ||||
|  | ||||
| const LABEL = 'label'; | ||||
| const RELATION = 'relation'; | ||||
| @@ -371,7 +370,7 @@ class FNote { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} [hoistedNoteId='root'] | ||||
|      * @return {Array<{isArchived: boolean, isInHoistedSubTree: boolean, notePath: Array<string>, isHidden: boolean}>} | ||||
|      * @return {Array<{isArchived: boolean, isInHoistedSubTree: boolean, isSearch: boolean, notePath: Array<string>, isHidden: boolean}>} | ||||
|      */ | ||||
|     getSortedNotePathRecords(hoistedNoteId = 'root') { | ||||
|         const isHoistedRoot = hoistedNoteId === 'root'; | ||||
| @@ -380,6 +379,7 @@ class FNote { | ||||
|             notePath: path, | ||||
|             isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId), | ||||
|             isArchived: path.some(noteId => froca.notes[noteId].isArchived), | ||||
|             isSearch: path.find(noteId => froca.notes[noteId].type === 'search'), | ||||
|             isHidden: path.includes('_hidden') | ||||
|         })); | ||||
|  | ||||
| @@ -390,6 +390,8 @@ class FNote { | ||||
|                 return a.isArchived ? 1 : -1; | ||||
|             } else if (a.isHidden !== b.isHidden) { | ||||
|                 return a.isHidden ? 1 : -1; | ||||
|             } else if (a.isSearch !== b.isSearch) { | ||||
|                 return a.isSearch ? 1 : -1; | ||||
|             } else { | ||||
|                 return a.notePath.length - b.notePath.length; | ||||
|             } | ||||
|   | ||||
| @@ -158,7 +158,7 @@ function renderFile(entity, type, $renderedContent) { | ||||
|         $content.append($pdfPreview); | ||||
|     } else if (type === 'audio') { | ||||
|         const $audioPreview = $('<audio controls></audio>') | ||||
|             .attr("src", openService.getUrlForStreaming(`api/${entityType}/${entityId}/open-partial`)) | ||||
|             .attr("src", openService.getUrlForDownload(`api/${entityType}/${entityId}/open-partial`)) | ||||
|             .attr("type", entity.mime) | ||||
|             .css("width", "100%"); | ||||
|  | ||||
|   | ||||
| @@ -478,7 +478,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | ||||
|      * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. | ||||
|      * | ||||
|      * @method | ||||
|      * @param {integer} length of the string | ||||
|      * @param {int} length of the string | ||||
|      * @returns {string} random string | ||||
|      */ | ||||
|     this.randomString = utils.randomString; | ||||
| @@ -488,7 +488,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | ||||
|      * @param {int} size in bytes | ||||
|      * @return {string} formatted string | ||||
|      */ | ||||
|     this.formatNoteSize = utils.formatNoteSize; | ||||
|     this.formatSize = utils.formatSize; | ||||
|  | ||||
|     /** | ||||
|      * @method | ||||
|      * @param {int} size in bytes | ||||
|      * @return {string} formatted string | ||||
|      * @deprecated - use api.formatSize() | ||||
|      */ | ||||
|     this.formatNoteSize = utils.formatSize; | ||||
|  | ||||
|     this.logMessages = {}; | ||||
|     this.logSpacedUpdates = {}; | ||||
|   | ||||
| @@ -93,7 +93,7 @@ async function createLink(notePath, options = {}) { | ||||
|     if (showNotePath) { | ||||
|         const resolvedNotePathSegments = await treeService.resolveNotePathToSegments(notePath); | ||||
|  | ||||
|         if (notePath) { | ||||
|         if (resolvedNotePathSegments) { | ||||
|             resolvedNotePathSegments.pop(); // remove last element | ||||
|  | ||||
|             const parentNotePath = resolvedNotePathSegments.join("/").trim(); | ||||
|   | ||||
| @@ -117,7 +117,7 @@ function getUrlForDownload(url) { | ||||
|         return `${getHost()}/${url}`; | ||||
|     } | ||||
|     else { | ||||
|         // web server can be deployed on subdomain, so we need to use relative path | ||||
|         // web server can be deployed on subdomain, so we need to use a relative path | ||||
|         return url; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,7 @@ async function resolveNotePath(notePath, hoistedNoteId = 'root') { | ||||
| /** | ||||
|  * Accepts notePath which might or might not be valid and returns an existing path as close to the original | ||||
|  * notePath as possible. Part of the path might not be valid because of note moving (which causes | ||||
|  * path change) or other corruption, in that case this will try to get some other valid path to the correct note. | ||||
|  * path change) or other corruption, in that case, this will try to get some other valid path to the correct note. | ||||
|  * | ||||
|  * @returns {Promise<string[]>} | ||||
|  */ | ||||
| @@ -27,7 +27,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr | ||||
|     notePath = notePath.split("?")[0].trim(); | ||||
|  | ||||
|     if (notePath.length === 0) { | ||||
|         return; | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     const path = notePath.split("/").reverse(); | ||||
| @@ -55,7 +55,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr | ||||
|                     ws.logError(`Can't find note ${childNoteId}`); | ||||
|                 } | ||||
|  | ||||
|                 return; | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             child.sortParents(); | ||||
| @@ -67,7 +67,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr | ||||
|                     ws.logError(`No parents found for note ${childNoteId} (${child.title}) for path ${notePath}`); | ||||
|                 } | ||||
|  | ||||
|                 return; | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             if (!parents.some(p => p.noteId === parentNoteId)) { | ||||
|   | ||||
| @@ -121,32 +121,6 @@ function escapeHtml(str) { | ||||
|     return str.replace(/[&<>"'`=\/]/g, s => entityMap[s]); | ||||
| } | ||||
|  | ||||
| async function stopWatch(what, func) { | ||||
|     const start = new Date(); | ||||
|  | ||||
|     const ret = await func(); | ||||
|  | ||||
|     const tookMs = Date.now() - start.getTime(); | ||||
|  | ||||
|     console.log(`${what} took ${tookMs}ms`); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| function formatValueWithWhitespace(val) { | ||||
|     return /[^\w-]/.test(val) ? `"${val}"` : val; | ||||
| } | ||||
|  | ||||
| function formatLabel(label) { | ||||
|     let str = `#${formatValueWithWhitespace(label.name)}`; | ||||
|  | ||||
|     if (label.value !== "") { | ||||
|         str += `=${formatValueWithWhitespace(label.value)}`; | ||||
|     } | ||||
|  | ||||
|     return str; | ||||
| } | ||||
|  | ||||
| function formatSize(size) { | ||||
|     size = Math.max(Math.round(size / 1024), 1); | ||||
|  | ||||
| @@ -203,15 +177,6 @@ function setCookie(name, value) { | ||||
|     document.cookie = `${name}=${value || ""}${expires};`; | ||||
| } | ||||
|  | ||||
| function setSessionCookie(name, value) { | ||||
|     document.cookie = `${name}=${value || ""}; SameSite=Strict`; | ||||
| } | ||||
|  | ||||
| function getCookie(name) { | ||||
|     const valueMatch = document.cookie.match(`(^|;) ?${name}=([^;]*)(;|$)`); | ||||
|     return valueMatch ? valueMatch[2] : null; | ||||
| } | ||||
|  | ||||
| function getNoteTypeClass(type) { | ||||
|     return `type-${type}`; | ||||
| } | ||||
| @@ -372,7 +337,7 @@ function openHelp(e) { | ||||
| } | ||||
|  | ||||
| function initHelpButtons($el) { | ||||
|     // for some reason the .on(event, listener, handler) does not work here (e.g. Options -> Sync -> Help button) | ||||
|     // for some reason, the .on(event, listener, handler) does not work here (e.g. Options -> Sync -> Help button) | ||||
|     // so we do it manually | ||||
|     $el.on("click", e => { | ||||
|         if ($(e.target).attr("data-help-page")) { | ||||
| @@ -525,24 +490,9 @@ function copyHtmlToClipboard(content) { | ||||
|     navigator.clipboard.write([clipboardItem]); | ||||
| } | ||||
|  | ||||
| function formatNoteSize(size) { | ||||
|     size = Math.max(Math.round(size / 1024), 1); | ||||
|  | ||||
|     if (size < 1024) { | ||||
|         return `${size} KiB`; | ||||
|     } | ||||
|     else { | ||||
|         return `${Math.round(size / 102.4) / 10} MiB`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| export default { | ||||
|     reloadFrontendApp, | ||||
|     parseDate, | ||||
|     padNum, | ||||
|     formatTime, | ||||
|     formatTimeWithSeconds, | ||||
|     formatDate, | ||||
|     formatDateISO, | ||||
|     formatDateTime, | ||||
|     formatTimeInterval, | ||||
| @@ -554,15 +504,11 @@ export default { | ||||
|     isCtrlKey, | ||||
|     assertArguments, | ||||
|     escapeHtml, | ||||
|     stopWatch, | ||||
|     formatLabel, | ||||
|     toObject, | ||||
|     randomString, | ||||
|     isMobile, | ||||
|     isDesktop, | ||||
|     setCookie, | ||||
|     setSessionCookie, | ||||
|     getCookie, | ||||
|     getNoteTypeClass, | ||||
|     getMimeTypeClass, | ||||
|     closeActiveDialog, | ||||
| @@ -581,7 +527,6 @@ export default { | ||||
|     isValidAttributeName, | ||||
|     sleep, | ||||
|     escapeRegExp, | ||||
|     formatNoteSize, | ||||
|     areObjectsEqual, | ||||
|     copyHtmlToClipboard | ||||
| }; | ||||
|   | ||||
| @@ -147,7 +147,7 @@ export default class RevisionsDialog extends BasicWidget { | ||||
|         for (const item of this.revisionItems) { | ||||
|             this.$list.append( | ||||
|                 $('<a class="dropdown-item" tabindex="0">') | ||||
|                     .text(`${item.dateLastEdited.substr(0, 16)} (${item.contentLength} bytes)`) | ||||
|                     .text(`${item.dateLastEdited.substr(0, 16)} (${utils.formatSize(item.contentLength)})`) | ||||
|                     .attr('data-revision-id', item.revisionId) | ||||
|                     .attr('title', `This revision was last edited on ${item.dateLastEdited}`) | ||||
|             ); | ||||
| @@ -259,7 +259,7 @@ export default class RevisionsDialog extends BasicWidget { | ||||
|                 )) | ||||
|                 .append($("<tr>").append( | ||||
|                     $("<th>").text("File size:"), | ||||
|                     $("<td>").text(`${revisionItem.contentLength} bytes`) | ||||
|                     $("<td>").text(utils.formatSize(revisionItem.contentLength)) | ||||
|                 )); | ||||
|  | ||||
|             if (fullRevision.content) { | ||||
|   | ||||
| @@ -42,7 +42,7 @@ export default class FindInCode { | ||||
|             // Find and highlight matches | ||||
|             // Find and highlight matches | ||||
|             // XXX Using \\b and not using the unicode flag probably doesn't | ||||
|             //     work with non ascii alphabets, findAndReplace uses a more | ||||
|             //     work with non-ASCII alphabets, findAndReplace uses a more | ||||
|             //     complicated regexp, see | ||||
|             //     https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/utils.js#L145 | ||||
|             const wholeWordChar = wholeWord ? "\\b" : ""; | ||||
| @@ -166,8 +166,6 @@ export default class FindInCode { | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         // Restore the highlightSelectionMatches setting | ||||
|         codeEditor.setOption("highlightSelectionMatches", this.oldHighlightSelectionMatches); | ||||
|         this.findResult = null; | ||||
|  | ||||
|         codeEditor.focus(); | ||||
|   | ||||
| @@ -125,18 +125,15 @@ export default class FilePropertiesWidget extends NoteContextAwareWidget { | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote(note) { | ||||
|         const attributes = note.getAttributes(); | ||||
|         const attributeMap = utils.toObject(attributes, l => [l.name, l.value]); | ||||
|  | ||||
|         this.$widget.show(); | ||||
|  | ||||
|         this.$fileNoteId.text(note.noteId); | ||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); | ||||
|         this.$fileName.text(note.getLabelValue('originalFileName') || "?"); | ||||
|         this.$fileType.text(note.mime); | ||||
|  | ||||
|         const blob = await this.note.getBlob(); | ||||
|  | ||||
|         this.$fileSize.text(utils.formatNoteSize(blob.contentLength)); | ||||
|         this.$fileSize.text(utils.formatSize(blob.contentLength)); | ||||
|  | ||||
|         // open doesn't work for protected notes since it works through a browser which isn't in protected session | ||||
|         this.$openButton.toggle(!note.isProtected); | ||||
|   | ||||
| @@ -111,15 +111,12 @@ export default class ImagePropertiesWidget extends NoteContextAwareWidget { | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote(note) { | ||||
|         const attributes = note.getAttributes(); | ||||
|         const attributeMap = utils.toObject(attributes, l => [l.name, l.value]); | ||||
|  | ||||
|         this.$widget.show(); | ||||
|  | ||||
|         const blob = await this.note.getBlob(); | ||||
|  | ||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); | ||||
|         this.$fileSize.text(`${blob.contentLength} bytes`); | ||||
|         this.$fileName.text(note.getLabelValue('originalFileName') || "?"); | ||||
|         this.$fileSize.text(utils.formatSize(blob.contentLength)); | ||||
|         this.$fileType.text(note.mime); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -106,12 +106,12 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { | ||||
|             this.$subTreeSize.empty().append($('<span class="bx bx-loader bx-spin"></span>')); | ||||
|  | ||||
|             const noteSizeResp = await server.get(`stats/note-size/${this.noteId}`); | ||||
|             this.$noteSize.text(utils.formatNoteSize(noteSizeResp.noteSize)); | ||||
|             this.$noteSize.text(utils.formatSize(noteSizeResp.noteSize)); | ||||
|  | ||||
|             const subTreeResp = await server.get(`stats/subtree-size/${this.noteId}`); | ||||
|  | ||||
|             if (subTreeResp.subTreeNoteCount > 1) { | ||||
|                 this.$subTreeSize.text(`(subtree size: ${utils.formatNoteSize(subTreeResp.subTreeSize)} in ${subTreeResp.subTreeNoteCount} notes)`); | ||||
|                 this.$subTreeSize.text(`(subtree size: ${utils.formatSize(subTreeResp.subTreeSize)} in ${subTreeResp.subTreeNoteCount} notes)`); | ||||
|             } | ||||
|             else { | ||||
|                 this.$subTreeSize.text(""); | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| import NoteContextAwareWidget from "../note_context_aware_widget.js"; | ||||
| import AttributeDetailWidget from "../attribute_widgets/attribute_detail.js"; | ||||
| import AttributeEditorWidget from "../attribute_widgets/attribute_editor.js"; | ||||
| import attributeService from "../../services/attributes.js"; | ||||
|  | ||||
| const TPL = ` | ||||
| <div class="attribute-list"> | ||||
|   | ||||
| @@ -88,11 +88,7 @@ export default class TocWidget extends RightPanelWidget { | ||||
|         * and then let it be displayed/hidden at the initial time. If there is no such value, | ||||
|         * when the right panel needs to display highlighttext but not toc, every time the note content is changed, | ||||
|         * toc will appear and then close immediately, because getToc(html) function will consume time*/ | ||||
|         if (this.noteContext.viewScope.tocPreviousVisible ==true){ | ||||
|             this.toggleInt(true); | ||||
|         }else{ | ||||
|             this.toggleInt(false); | ||||
|         } | ||||
|         this.toggleInt(!!this.noteContext.viewScope.tocPreviousVisible); | ||||
|  | ||||
|         const tocLabel = note.getLabel('toc'); | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| import AbstractTextTypeWidget from "./abstract_text_type_widget.js"; | ||||
| import treeService from "../../services/tree.js"; | ||||
| import libraryLoader from "../../services/library_loader.js"; | ||||
|  | ||||
| const TPL = ` | ||||
|   | ||||
| @@ -62,10 +62,7 @@ span.fancytree-node.fancytree-hide { | ||||
|     display: inline-block; | ||||
|     width: 16px; | ||||
|     height: 16px; | ||||
|     margin-left: 5px; | ||||
|     margin-right: 8px; | ||||
|     margin-top: 4px; | ||||
|     margin-bottom: 2px; | ||||
|     margin: 4px 8px 2px 5px; | ||||
| } | ||||
|  | ||||
| .fancytree-loading span.fancytree-expander:after { | ||||
|   | ||||
| @@ -35,7 +35,7 @@ function buildDescendantCountMap(noteIdsToCount) { | ||||
| } | ||||
| /** | ||||
|  * @param {BNote} note | ||||
|  * @param {integer} depth | ||||
|  * @param {int} depth | ||||
|  * @returns {string[]} noteIds | ||||
|  */ | ||||
| function getNeighbors(note, depth) { | ||||
|   | ||||
| @@ -15,7 +15,7 @@ const appPath = require("../services/app_path"); | ||||
| function index(req, res) { | ||||
|     const options = optionService.getOptionMap(); | ||||
|  | ||||
|     let view = (!utils.isElectron() && req.cookies['trilium-device'] === 'mobile') | ||||
|     const view = (!utils.isElectron() && req.cookies['trilium-device'] === 'mobile') | ||||
|         ? 'mobile' | ||||
|         : 'desktop'; | ||||
|  | ||||
| @@ -47,18 +47,14 @@ function index(req, res) { | ||||
| function getThemeCssUrl(theme) { | ||||
|     if (theme === 'light') { | ||||
|         return false; // light theme is always loaded as baseline | ||||
|     } | ||||
|  | ||||
|     if (theme === 'dark') { | ||||
|     } else if (theme === 'dark') { | ||||
|         return `${assetPath}/stylesheets/theme-dark.css`; | ||||
|     } | ||||
|     else { | ||||
|     } else { | ||||
|         const themeNote = attributeService.getNoteWithLabel('appTheme', theme); | ||||
|  | ||||
|         if (themeNote) { | ||||
|             return `api/notes/download/${themeNote.noteId}`; | ||||
|         } | ||||
|         else { | ||||
|         } else { | ||||
|             return false; // baseline light theme | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -59,7 +59,7 @@ function login(req, res) { | ||||
|     const guessedPassword = req.body.password; | ||||
|  | ||||
|     if (verifyPassword(guessedPassword)) { | ||||
|         const rememberMe = req.body.remember_me; | ||||
|         const rememberMe = req.body.rememberMe; | ||||
|  | ||||
|         req.session.regenerate(() => { | ||||
|             if (rememberMe) { | ||||
|   | ||||
| @@ -21,8 +21,8 @@ function setupPage(req, res) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // we got here because DB is not completely initialized so if schema exists | ||||
|     // it means we're in sync in progress state. | ||||
|     // we got here because DB is not completely initialized, so if schema exists, | ||||
|     // it means we're in "sync in progress" state. | ||||
|     const syncInProgress = sqlInit.schemaExists(); | ||||
|  | ||||
|     if (syncInProgress) { | ||||
|   | ||||
| @@ -215,7 +215,7 @@ function BackendScriptApi(currentNote, apiParams) { | ||||
|      * @property {boolean} [params.isProtected=false] | ||||
|      * @property {boolean} [params.isExpanded=false] | ||||
|      * @property {string} [params.prefix=''] | ||||
|      * @property {integer} [params.notePosition] - default is last existing notePosition in a parent + 10 | ||||
|      * @property {int} [params.notePosition] - default is last existing notePosition in a parent + 10 | ||||
|      * @returns {{note: BNote, branch: BBranch}} object contains newly created entities note and branch | ||||
|      */ | ||||
|     this.createNewNote = noteService.createNewNote; | ||||
| @@ -412,7 +412,7 @@ function BackendScriptApi(currentNote, apiParams) { | ||||
|      * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. | ||||
|      * | ||||
|      * @method | ||||
|      * @param {integer} length of the string | ||||
|      * @param {int} length of the string | ||||
|      * @returns {string} random string | ||||
|      */ | ||||
|     this.randomString = utils.randomString; | ||||
|   | ||||
| @@ -59,9 +59,9 @@ function cloneNoteToBranch(noteId, parentBranchId, prefix) { | ||||
| } | ||||
|  | ||||
| function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) { | ||||
|     if (isNoteDeleted(noteId)) { | ||||
|     if (!(noteId in becca.notes)) { | ||||
|         return { branch: null, success: false, message: `Note '${noteId}' is deleted.` }; | ||||
|     } else if (isNoteDeleted(parentNoteId)) { | ||||
|     } else if (!(parentNoteId in becca.notes)) { | ||||
|         return { branch: null, success: false, message: `Note '${parentNoteId}' is deleted.` }; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -40,7 +40,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | ||||
|     const noteIdToMeta = {}; | ||||
|  | ||||
|     /** | ||||
|      * @param {Object.<string, integer>} existingFileNames | ||||
|      * @param {Object.<string, int>} existingFileNames | ||||
|      * @param {string} fileName | ||||
|      * @returns {string} | ||||
|      */ | ||||
| @@ -60,7 +60,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | ||||
|  | ||||
|             return `${index}_${fileName}`; | ||||
|         } | ||||
|         else {[] | ||||
|         else { | ||||
|             existingFileNames[lcFileName] = 1; | ||||
|  | ||||
|             return fileName; | ||||
| @@ -71,7 +71,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | ||||
|      * @param {string|null} type | ||||
|      * @param {string} mime | ||||
|      * @param {string} baseFileName | ||||
|      * @param {Object.<string, integer>} existingFileNames | ||||
|      * @param {Object.<string, int>} existingFileNames | ||||
|      * @return {string} | ||||
|      */ | ||||
|     function getDataFileName(type, mime, baseFileName, existingFileNames) { | ||||
| @@ -119,7 +119,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | ||||
|     /** | ||||
|      * @param {BBranch} branch | ||||
|      * @param {NoteMeta} parentMeta | ||||
|      * @param {Object.<string, integer>} existingFileNames | ||||
|      * @param {Object.<string, int>} existingFileNames | ||||
|      * @returns {NoteMeta|null} | ||||
|      */ | ||||
|     function createNoteMeta(branch, parentMeta, existingFileNames) { | ||||
|   | ||||
| @@ -7,7 +7,7 @@ class AttachmentMeta { | ||||
|     role; | ||||
|     /** @type {string} */ | ||||
|     mime; | ||||
|     /** @type {integer} */ | ||||
|     /** @type {int} */ | ||||
|     position; | ||||
|     /** @type {string} */ | ||||
|     dataFileName; | ||||
|   | ||||
| @@ -7,7 +7,7 @@ class AttributeMeta { | ||||
|     value; | ||||
|     /** @type {boolean} */ | ||||
|     isInheritable; | ||||
|     /** @type {integer} */ | ||||
|     /** @type {int} */ | ||||
|     position; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,7 @@ class NoteMeta { | ||||
|     isClone; | ||||
|     /** @type {string} */ | ||||
|     title; | ||||
|     /** @type {integer} */ | ||||
|     /** @type {int} */ | ||||
|     notePosition; | ||||
|     /** @type {string} */ | ||||
|     prefix; | ||||
|   | ||||
| @@ -152,7 +152,7 @@ function getAndValidateParent(params) { | ||||
|  * - {boolean} isProtected - default is false | ||||
|  * - {boolean} isExpanded - default is false | ||||
|  * - {string} prefix - default is empty string | ||||
|  * - {integer} notePosition - default is last existing notePosition in a parent + 10 | ||||
|  * - {int} notePosition - default is last existing notePosition in a parent + 10 | ||||
|  * | ||||
|  * @param params | ||||
|  * @returns {{note: BNote, branch: BBranch}} | ||||
|   | ||||
| @@ -26,7 +26,7 @@ function getOption(name) { | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| /** @returns {integer} */ | ||||
| /** @returns {int} */ | ||||
| function getOptionInt(name, defaultValue = undefined) { | ||||
|     const val = getOption(name); | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,6 @@ const escape = require('escape-html'); | ||||
| const sanitize = require("sanitize-filename"); | ||||
| const mimeTypes = require('mime-types'); | ||||
| const path = require('path'); | ||||
| const log = require('./log'); | ||||
|  | ||||
| function newEntityId() { | ||||
|     return randomString(12); | ||||
| @@ -33,11 +32,6 @@ function hashedBlobId(content) { | ||||
|     return base64Hash.substr(0, 20); | ||||
| } | ||||
|  | ||||
| function randomBlobId(content) { | ||||
|     // underscore prefix to easily differentiate the random as opposed to hashed | ||||
|     return '_' + randomString(19); | ||||
| } | ||||
|  | ||||
| function toBase64(plainText) { | ||||
|     return Buffer.from(plainText).toString('base64'); | ||||
| } | ||||
| @@ -71,30 +65,6 @@ function sanitizeSqlIdentifier(str) { | ||||
|     return str.replace(/[^A-Za-z0-9_]/g, ""); | ||||
| } | ||||
|  | ||||
| function prepareSqlForLike(prefix, str, suffix) { | ||||
|     const value = str | ||||
|         .replace(/\\/g, "\\\\") | ||||
|         .replace(/'/g, "''") | ||||
|         .replace(/_/g, "\\_") | ||||
|         .replace(/%/g, "\\%"); | ||||
|  | ||||
|     return `'${prefix}${value}${suffix}' ESCAPE '\\'`; | ||||
| } | ||||
|  | ||||
| function stopWatch(what, func, timeLimit = 0) { | ||||
|     const start = Date.now(); | ||||
|  | ||||
|     const ret = func(); | ||||
|  | ||||
|     const tookMs = Date.now() - start; | ||||
|  | ||||
|     if (tookMs >= timeLimit) { | ||||
|         log.info(`${what} took ${tookMs}ms`); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| function escapeHtml(str) { | ||||
|     return escape(str); | ||||
| } | ||||
| @@ -119,10 +89,6 @@ function stripTags(text) { | ||||
|     return text.replace(/<(?:.|\n)*?>/gm, ''); | ||||
| } | ||||
|  | ||||
| function intersection(a, b) { | ||||
|     return a.filter(value => b.indexOf(value) !== -1); | ||||
| } | ||||
|  | ||||
| function union(a, b) { | ||||
|     const obj = {}; | ||||
|  | ||||
| @@ -231,7 +197,7 @@ function formatDownloadTitle(fileName, type, mime) { | ||||
|  | ||||
|         if (mime === 'application/octet-stream') { | ||||
|             // we didn't find any good guess for this one, it will be better to just return | ||||
|             // the current name without fake extension. It's possible that the title still preserves to correct | ||||
|             // the current name without a fake extension. It's possible that the title still preserves the correct | ||||
|             // extension too | ||||
|  | ||||
|             return fileName; | ||||
| @@ -318,10 +284,6 @@ function normalize(str) { | ||||
|     return removeDiacritic(str).toLowerCase(); | ||||
| } | ||||
|  | ||||
| function filterAttributeName(name) { | ||||
|     return name.replace(/[^\p{L}\p{N}_:]/ug, ""); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     randomSecureToken, | ||||
|     randomString, | ||||
| @@ -334,17 +296,13 @@ module.exports = { | ||||
|     hash, | ||||
|     isEmptyOrWhitespace, | ||||
|     sanitizeSqlIdentifier, | ||||
|     prepareSqlForLike, | ||||
|     stopWatch, | ||||
|     escapeHtml, | ||||
|     unescapeHtml, | ||||
|     toObject, | ||||
|     stripTags, | ||||
|     intersection, | ||||
|     union, | ||||
|     escapeRegExp, | ||||
|     crash, | ||||
|     sanitizeFilenameForHeader, | ||||
|     getContentDisposition, | ||||
|     isStringNote, | ||||
|     quoteRegex, | ||||
| @@ -356,7 +314,5 @@ module.exports = { | ||||
|     deferred, | ||||
|     removeDiacritic, | ||||
|     normalize, | ||||
|     filterAttributeName, | ||||
|     hashedBlobId, | ||||
|     randomBlobId | ||||
| }; | ||||
|   | ||||
| @@ -14,7 +14,7 @@ class SAttribute extends AbstractShacaEntity { | ||||
|         this.type = type; | ||||
|         /** @param {string} */ | ||||
|         this.name = name; | ||||
|         /** @param {integer} */ | ||||
|         /** @param {int} */ | ||||
|         this.position = position; | ||||
|         /** @param {string} */ | ||||
|         this.value = value; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class Shaca { | ||||
|         this.attributes = {}; | ||||
|         /** @type {Object.<String, SAttachment>} */ | ||||
|         this.attachments = {}; | ||||
|         /** @type {Object.<String, String>} */ | ||||
|         /** @type {Object.<String, SNote>} */ | ||||
|         this.aliasToNote = {}; | ||||
|  | ||||
|         /** @type {SNote|null} */ | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
|             <div class="form-group"> | ||||
|                 <div class="checkbox"> | ||||
|                     <label> | ||||
|                         <input id="remember-me" name="remember_me" value="1" type="checkbox"> Remember me | ||||
|                         <input id="remember-me" name="rememberMe" value="1" type="checkbox"> Remember me | ||||
|                     </label> | ||||
|                 </div> | ||||
|             </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user