mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 21:11:30 +08:00 
			
		
		
		
	small refactorings and fixes
This commit is contained in:
		
							parent
							
								
									48029cea7c
								
							
						
					
					
						commit
						eb34f9c64f
					
				| @ -5,7 +5,8 @@ const NoteSet = require("../services/search/note_set"); | |||||||
| const NotFoundError = require("../errors/not_found_error"); | 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 { | class Becca { | ||||||
|     constructor() { |     constructor() { | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ function load() { | |||||||
|     becca.reset(); |     becca.reset(); | ||||||
| 
 | 
 | ||||||
|     // using a raw query and passing arrays to avoid allocating new objects,
 |     // 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`)) { |     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(); |         new BNote().update(row).init(); | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ class BAttachment extends AbstractBeccaEntity { | |||||||
|         this.mime = row.mime; |         this.mime = row.mime; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.title = row.title; |         this.title = row.title; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.position = row.position; |         this.position = row.position; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.blobId = row.blobId; |         this.blobId = row.blobId; | ||||||
| @ -59,7 +59,7 @@ class BAttachment extends AbstractBeccaEntity { | |||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; |         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||||
| 
 | 
 | ||||||
|         /** @type {integer} optionally added to the entity */ |         /** @type {int} optionally added to the entity */ | ||||||
|         this.contentLength = row.contentLength; |         this.contentLength = row.contentLength; | ||||||
| 
 | 
 | ||||||
|         this.decrypt(); |         this.decrypt(); | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ class BAttribute extends AbstractBeccaEntity { | |||||||
|         this.type = type; |         this.type = type; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.name = name; |         this.name = name; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.position = position; |         this.position = position; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.value = value || ""; |         this.value = value || ""; | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ class BBlob { | |||||||
|         this.blobId = row.blobId; |         this.blobId = row.blobId; | ||||||
|         /** @type {string|Buffer} */ |         /** @type {string|Buffer} */ | ||||||
|         this.content = row.content; |         this.content = row.content; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.contentLength = row.contentLength; |         this.contentLength = row.contentLength; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.dateModified = row.dateModified; |         this.dateModified = row.dateModified; | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ class BBranch extends AbstractBeccaEntity { | |||||||
|         this.parentNoteId = parentNoteId; |         this.parentNoteId = parentNoteId; | ||||||
|         /** @type {string|null} */ |         /** @type {string|null} */ | ||||||
|         this.prefix = prefix; |         this.prefix = prefix; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.notePosition = notePosition; |         this.notePosition = notePosition; | ||||||
|         /** @type {boolean} */ |         /** @type {boolean} */ | ||||||
|         this.isExpanded = !!isExpanded; |         this.isExpanded = !!isExpanded; | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ class BRevision extends AbstractBeccaEntity { | |||||||
|         this.utcDateCreated = row.utcDateCreated; |         this.utcDateCreated = row.utcDateCreated; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.utcDateModified = row.utcDateModified; |         this.utcDateModified = row.utcDateModified; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.contentLength = row.contentLength; |         this.contentLength = row.contentLength; | ||||||
| 
 | 
 | ||||||
|         if (this.isProtected && !titleDecrypted) { |         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
 |         // 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("h1", 0.9); | ||||||
|         addHeadingsToRewardMap("h2", 0.9); |         addHeadingsToRewardMap("h2", 0.9); | ||||||
|         addHeadingsToRewardMap("h3", 0.8); |         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/
 |  * see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
 | ||||||
|  */ |  */ | ||||||
| function setImmediatePromise() { | 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.`); |             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)); |         res.setHeader('Content-Disposition', utils.getContentDisposition(filename)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,7 +6,6 @@ import options from "../services/options.js"; | |||||||
| import utils from "../services/utils.js"; | import utils from "../services/utils.js"; | ||||||
| import zoomComponent from "./zoom.js"; | import zoomComponent from "./zoom.js"; | ||||||
| import TabManager from "./tab_manager.js"; | import TabManager from "./tab_manager.js"; | ||||||
| import treeService from "../services/tree.js"; |  | ||||||
| import Component from "./component.js"; | import Component from "./component.js"; | ||||||
| import keyboardActionsService from "../services/keyboard_actions.js"; | import keyboardActionsService from "../services/keyboard_actions.js"; | ||||||
| import linkService from "../services/link.js"; | import linkService from "../services/link.js"; | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ class FAttachment { | |||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; |         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||||
| 
 | 
 | ||||||
|         /** @type {integer} optionally added to the entity */ |         /** @type {int} optionally added to the entity */ | ||||||
|         this.contentLength = row.contentLength; |         this.contentLength = row.contentLength; | ||||||
| 
 | 
 | ||||||
|         this.froca.attachments[this.attachmentId] = this; |         this.froca.attachments[this.attachmentId] = this; | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ class FAttribute { | |||||||
|         this.name = row.name; |         this.name = row.name; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.value = row.value; |         this.value = row.value; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.position = row.position; |         this.position = row.position; | ||||||
|         /** @type {boolean} */ |         /** @type {boolean} */ | ||||||
|         this.isInheritable = !!row.isInheritable; |         this.isInheritable = !!row.isInheritable; | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ class FBranch { | |||||||
|         this.noteId = row.noteId; |         this.noteId = row.noteId; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.parentNoteId = row.parentNoteId; |         this.parentNoteId = row.parentNoteId; | ||||||
|         /** @type {integer} */ |         /** @type {int} */ | ||||||
|         this.notePosition = row.notePosition; |         this.notePosition = row.notePosition; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.prefix = row.prefix; |         this.prefix = row.prefix; | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import ws from "../services/ws.js"; | |||||||
| import froca from "../services/froca.js"; | import froca from "../services/froca.js"; | ||||||
| import protectedSessionHolder from "../services/protected_session_holder.js"; | import protectedSessionHolder from "../services/protected_session_holder.js"; | ||||||
| import cssClassManager from "../services/css_class_manager.js"; | import cssClassManager from "../services/css_class_manager.js"; | ||||||
| import FAttachment from "./fattachment.js"; |  | ||||||
| 
 | 
 | ||||||
| const LABEL = 'label'; | const LABEL = 'label'; | ||||||
| const RELATION = 'relation'; | const RELATION = 'relation'; | ||||||
| @ -371,7 +370,7 @@ class FNote { | |||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @param {string} [hoistedNoteId='root'] |      * @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') { |     getSortedNotePathRecords(hoistedNoteId = 'root') { | ||||||
|         const isHoistedRoot = hoistedNoteId === 'root'; |         const isHoistedRoot = hoistedNoteId === 'root'; | ||||||
| @ -380,6 +379,7 @@ class FNote { | |||||||
|             notePath: path, |             notePath: path, | ||||||
|             isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId), |             isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId), | ||||||
|             isArchived: path.some(noteId => froca.notes[noteId].isArchived), |             isArchived: path.some(noteId => froca.notes[noteId].isArchived), | ||||||
|  |             isSearch: path.find(noteId => froca.notes[noteId].type === 'search'), | ||||||
|             isHidden: path.includes('_hidden') |             isHidden: path.includes('_hidden') | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
| @ -390,6 +390,8 @@ class FNote { | |||||||
|                 return a.isArchived ? 1 : -1; |                 return a.isArchived ? 1 : -1; | ||||||
|             } else if (a.isHidden !== b.isHidden) { |             } else if (a.isHidden !== b.isHidden) { | ||||||
|                 return a.isHidden ? 1 : -1; |                 return a.isHidden ? 1 : -1; | ||||||
|  |             } else if (a.isSearch !== b.isSearch) { | ||||||
|  |                 return a.isSearch ? 1 : -1; | ||||||
|             } else { |             } else { | ||||||
|                 return a.notePath.length - b.notePath.length; |                 return a.notePath.length - b.notePath.length; | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -158,7 +158,7 @@ function renderFile(entity, type, $renderedContent) { | |||||||
|         $content.append($pdfPreview); |         $content.append($pdfPreview); | ||||||
|     } else if (type === 'audio') { |     } else if (type === 'audio') { | ||||||
|         const $audioPreview = $('<audio controls></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) |             .attr("type", entity.mime) | ||||||
|             .css("width", "100%"); |             .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. |      * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. | ||||||
|      * |      * | ||||||
|      * @method |      * @method | ||||||
|      * @param {integer} length of the string |      * @param {int} length of the string | ||||||
|      * @returns {string} random string |      * @returns {string} random string | ||||||
|      */ |      */ | ||||||
|     this.randomString = utils.randomString; |     this.randomString = utils.randomString; | ||||||
| @ -488,7 +488,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | |||||||
|      * @param {int} size in bytes |      * @param {int} size in bytes | ||||||
|      * @return {string} formatted string |      * @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.logMessages = {}; | ||||||
|     this.logSpacedUpdates = {}; |     this.logSpacedUpdates = {}; | ||||||
|  | |||||||
| @ -93,7 +93,7 @@ async function createLink(notePath, options = {}) { | |||||||
|     if (showNotePath) { |     if (showNotePath) { | ||||||
|         const resolvedNotePathSegments = await treeService.resolveNotePathToSegments(notePath); |         const resolvedNotePathSegments = await treeService.resolveNotePathToSegments(notePath); | ||||||
| 
 | 
 | ||||||
|         if (notePath) { |         if (resolvedNotePathSegments) { | ||||||
|             resolvedNotePathSegments.pop(); // remove last element
 |             resolvedNotePathSegments.pop(); // remove last element
 | ||||||
| 
 | 
 | ||||||
|             const parentNotePath = resolvedNotePathSegments.join("/").trim(); |             const parentNotePath = resolvedNotePathSegments.join("/").trim(); | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ function getUrlForDownload(url) { | |||||||
|         return `${getHost()}/${url}`; |         return `${getHost()}/${url}`; | ||||||
|     } |     } | ||||||
|     else { |     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; |         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 |  * 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 |  * 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[]>} |  * @returns {Promise<string[]>} | ||||||
|  */ |  */ | ||||||
| @ -27,7 +27,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr | |||||||
|     notePath = notePath.split("?")[0].trim(); |     notePath = notePath.split("?")[0].trim(); | ||||||
| 
 | 
 | ||||||
|     if (notePath.length === 0) { |     if (notePath.length === 0) { | ||||||
|         return; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const path = notePath.split("/").reverse(); |     const path = notePath.split("/").reverse(); | ||||||
| @ -55,7 +55,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr | |||||||
|                     ws.logError(`Can't find note ${childNoteId}`); |                     ws.logError(`Can't find note ${childNoteId}`); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 return; |                 return null; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             child.sortParents(); |             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}`); |                     ws.logError(`No parents found for note ${childNoteId} (${child.title}) for path ${notePath}`); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 return; |                 return null; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (!parents.some(p => p.noteId === parentNoteId)) { |             if (!parents.some(p => p.noteId === parentNoteId)) { | ||||||
|  | |||||||
| @ -121,32 +121,6 @@ function escapeHtml(str) { | |||||||
|     return str.replace(/[&<>"'`=\/]/g, s => entityMap[s]); |     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) { | function formatSize(size) { | ||||||
|     size = Math.max(Math.round(size / 1024), 1); |     size = Math.max(Math.round(size / 1024), 1); | ||||||
| 
 | 
 | ||||||
| @ -203,15 +177,6 @@ function setCookie(name, value) { | |||||||
|     document.cookie = `${name}=${value || ""}${expires};`; |     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) { | function getNoteTypeClass(type) { | ||||||
|     return `type-${type}`; |     return `type-${type}`; | ||||||
| } | } | ||||||
| @ -372,7 +337,7 @@ function openHelp(e) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function initHelpButtons($el) { | 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
 |     // so we do it manually
 | ||||||
|     $el.on("click", e => { |     $el.on("click", e => { | ||||||
|         if ($(e.target).attr("data-help-page")) { |         if ($(e.target).attr("data-help-page")) { | ||||||
| @ -525,24 +490,9 @@ function copyHtmlToClipboard(content) { | |||||||
|     navigator.clipboard.write([clipboardItem]); |     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 { | export default { | ||||||
|     reloadFrontendApp, |     reloadFrontendApp, | ||||||
|     parseDate, |     parseDate, | ||||||
|     padNum, |  | ||||||
|     formatTime, |  | ||||||
|     formatTimeWithSeconds, |  | ||||||
|     formatDate, |  | ||||||
|     formatDateISO, |     formatDateISO, | ||||||
|     formatDateTime, |     formatDateTime, | ||||||
|     formatTimeInterval, |     formatTimeInterval, | ||||||
| @ -554,15 +504,11 @@ export default { | |||||||
|     isCtrlKey, |     isCtrlKey, | ||||||
|     assertArguments, |     assertArguments, | ||||||
|     escapeHtml, |     escapeHtml, | ||||||
|     stopWatch, |  | ||||||
|     formatLabel, |  | ||||||
|     toObject, |     toObject, | ||||||
|     randomString, |     randomString, | ||||||
|     isMobile, |     isMobile, | ||||||
|     isDesktop, |     isDesktop, | ||||||
|     setCookie, |     setCookie, | ||||||
|     setSessionCookie, |  | ||||||
|     getCookie, |  | ||||||
|     getNoteTypeClass, |     getNoteTypeClass, | ||||||
|     getMimeTypeClass, |     getMimeTypeClass, | ||||||
|     closeActiveDialog, |     closeActiveDialog, | ||||||
| @ -581,7 +527,6 @@ export default { | |||||||
|     isValidAttributeName, |     isValidAttributeName, | ||||||
|     sleep, |     sleep, | ||||||
|     escapeRegExp, |     escapeRegExp, | ||||||
|     formatNoteSize, |  | ||||||
|     areObjectsEqual, |     areObjectsEqual, | ||||||
|     copyHtmlToClipboard |     copyHtmlToClipboard | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -147,7 +147,7 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|         for (const item of this.revisionItems) { |         for (const item of this.revisionItems) { | ||||||
|             this.$list.append( |             this.$list.append( | ||||||
|                 $('<a class="dropdown-item" tabindex="0">') |                 $('<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('data-revision-id', item.revisionId) | ||||||
|                     .attr('title', `This revision was last edited on ${item.dateLastEdited}`) |                     .attr('title', `This revision was last edited on ${item.dateLastEdited}`) | ||||||
|             ); |             ); | ||||||
| @ -259,7 +259,7 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|                 )) |                 )) | ||||||
|                 .append($("<tr>").append( |                 .append($("<tr>").append( | ||||||
|                     $("<th>").text("File size:"), |                     $("<th>").text("File size:"), | ||||||
|                     $("<td>").text(`${revisionItem.contentLength} bytes`) |                     $("<td>").text(utils.formatSize(revisionItem.contentLength)) | ||||||
|                 )); |                 )); | ||||||
| 
 | 
 | ||||||
|             if (fullRevision.content) { |             if (fullRevision.content) { | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ export default class FindInCode { | |||||||
|             // Find and highlight matches
 |             // Find and highlight matches
 | ||||||
|             // Find and highlight matches
 |             // Find and highlight matches
 | ||||||
|             // XXX Using \\b and not using the unicode flag probably doesn't
 |             // 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
 |             //     complicated regexp, see
 | ||||||
|             //     https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/utils.js#L145
 |             //     https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/utils.js#L145
 | ||||||
|             const wholeWordChar = wholeWord ? "\\b" : ""; |             const wholeWordChar = wholeWord ? "\\b" : ""; | ||||||
| @ -166,8 +166,6 @@ export default class FindInCode { | |||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         // Restore the highlightSelectionMatches setting
 |  | ||||||
|         codeEditor.setOption("highlightSelectionMatches", this.oldHighlightSelectionMatches); |  | ||||||
|         this.findResult = null; |         this.findResult = null; | ||||||
| 
 | 
 | ||||||
|         codeEditor.focus(); |         codeEditor.focus(); | ||||||
|  | |||||||
| @ -125,18 +125,15 @@ export default class FilePropertiesWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async refreshWithNote(note) { |     async refreshWithNote(note) { | ||||||
|         const attributes = note.getAttributes(); |  | ||||||
|         const attributeMap = utils.toObject(attributes, l => [l.name, l.value]); |  | ||||||
| 
 |  | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
| 
 | 
 | ||||||
|         this.$fileNoteId.text(note.noteId); |         this.$fileNoteId.text(note.noteId); | ||||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); |         this.$fileName.text(note.getLabelValue('originalFileName') || "?"); | ||||||
|         this.$fileType.text(note.mime); |         this.$fileType.text(note.mime); | ||||||
| 
 | 
 | ||||||
|         const blob = await this.note.getBlob(); |         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
 |         // open doesn't work for protected notes since it works through a browser which isn't in protected session
 | ||||||
|         this.$openButton.toggle(!note.isProtected); |         this.$openButton.toggle(!note.isProtected); | ||||||
|  | |||||||
| @ -111,15 +111,12 @@ export default class ImagePropertiesWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async refreshWithNote(note) { |     async refreshWithNote(note) { | ||||||
|         const attributes = note.getAttributes(); |  | ||||||
|         const attributeMap = utils.toObject(attributes, l => [l.name, l.value]); |  | ||||||
| 
 |  | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
| 
 | 
 | ||||||
|         const blob = await this.note.getBlob(); |         const blob = await this.note.getBlob(); | ||||||
| 
 | 
 | ||||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); |         this.$fileName.text(note.getLabelValue('originalFileName') || "?"); | ||||||
|         this.$fileSize.text(`${blob.contentLength} bytes`); |         this.$fileSize.text(utils.formatSize(blob.contentLength)); | ||||||
|         this.$fileType.text(note.mime); |         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>')); |             this.$subTreeSize.empty().append($('<span class="bx bx-loader bx-spin"></span>')); | ||||||
| 
 | 
 | ||||||
|             const noteSizeResp = await server.get(`stats/note-size/${this.noteId}`); |             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}`); |             const subTreeResp = await server.get(`stats/subtree-size/${this.noteId}`); | ||||||
| 
 | 
 | ||||||
|             if (subTreeResp.subTreeNoteCount > 1) { |             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 { |             else { | ||||||
|                 this.$subTreeSize.text(""); |                 this.$subTreeSize.text(""); | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| import NoteContextAwareWidget from "../note_context_aware_widget.js"; | import NoteContextAwareWidget from "../note_context_aware_widget.js"; | ||||||
| import AttributeDetailWidget from "../attribute_widgets/attribute_detail.js"; | import AttributeDetailWidget from "../attribute_widgets/attribute_detail.js"; | ||||||
| import AttributeEditorWidget from "../attribute_widgets/attribute_editor.js"; | import AttributeEditorWidget from "../attribute_widgets/attribute_editor.js"; | ||||||
| import attributeService from "../../services/attributes.js"; |  | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="attribute-list"> | <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, |         * 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, |         * 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*/ |         * toc will appear and then close immediately, because getToc(html) function will consume time*/ | ||||||
|         if (this.noteContext.viewScope.tocPreviousVisible ==true){ |         this.toggleInt(!!this.noteContext.viewScope.tocPreviousVisible); | ||||||
|             this.toggleInt(true); |  | ||||||
|         }else{ |  | ||||||
|             this.toggleInt(false); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         const tocLabel = note.getLabel('toc'); |         const tocLabel = note.getLabel('toc'); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| import AbstractTextTypeWidget from "./abstract_text_type_widget.js"; | import AbstractTextTypeWidget from "./abstract_text_type_widget.js"; | ||||||
| import treeService from "../../services/tree.js"; |  | ||||||
| import libraryLoader from "../../services/library_loader.js"; | import libraryLoader from "../../services/library_loader.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
|  | |||||||
| @ -62,10 +62,7 @@ span.fancytree-node.fancytree-hide { | |||||||
|     display: inline-block; |     display: inline-block; | ||||||
|     width: 16px; |     width: 16px; | ||||||
|     height: 16px; |     height: 16px; | ||||||
|     margin-left: 5px; |     margin: 4px 8px 2px 5px; | ||||||
|     margin-right: 8px; |  | ||||||
|     margin-top: 4px; |  | ||||||
|     margin-bottom: 2px; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .fancytree-loading span.fancytree-expander:after { | .fancytree-loading span.fancytree-expander:after { | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ function buildDescendantCountMap(noteIdsToCount) { | |||||||
| } | } | ||||||
| /** | /** | ||||||
|  * @param {BNote} note |  * @param {BNote} note | ||||||
|  * @param {integer} depth |  * @param {int} depth | ||||||
|  * @returns {string[]} noteIds |  * @returns {string[]} noteIds | ||||||
|  */ |  */ | ||||||
| function getNeighbors(note, depth) { | function getNeighbors(note, depth) { | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ const appPath = require("../services/app_path"); | |||||||
| function index(req, res) { | function index(req, res) { | ||||||
|     const options = optionService.getOptionMap(); |     const options = optionService.getOptionMap(); | ||||||
| 
 | 
 | ||||||
|     let view = (!utils.isElectron() && req.cookies['trilium-device'] === 'mobile') |     const view = (!utils.isElectron() && req.cookies['trilium-device'] === 'mobile') | ||||||
|         ? 'mobile' |         ? 'mobile' | ||||||
|         : 'desktop'; |         : 'desktop'; | ||||||
| 
 | 
 | ||||||
| @ -47,18 +47,14 @@ function index(req, res) { | |||||||
| function getThemeCssUrl(theme) { | function getThemeCssUrl(theme) { | ||||||
|     if (theme === 'light') { |     if (theme === 'light') { | ||||||
|         return false; // light theme is always loaded as baseline
 |         return false; // light theme is always loaded as baseline
 | ||||||
|     } |     } else if (theme === 'dark') { | ||||||
| 
 |  | ||||||
|     if (theme === 'dark') { |  | ||||||
|         return `${assetPath}/stylesheets/theme-dark.css`; |         return `${assetPath}/stylesheets/theme-dark.css`; | ||||||
|     } |     } else { | ||||||
|     else { |  | ||||||
|         const themeNote = attributeService.getNoteWithLabel('appTheme', theme); |         const themeNote = attributeService.getNoteWithLabel('appTheme', theme); | ||||||
| 
 | 
 | ||||||
|         if (themeNote) { |         if (themeNote) { | ||||||
|             return `api/notes/download/${themeNote.noteId}`; |             return `api/notes/download/${themeNote.noteId}`; | ||||||
|         } |         } else { | ||||||
|         else { |  | ||||||
|             return false; // baseline light theme
 |             return false; // baseline light theme
 | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -59,7 +59,7 @@ function login(req, res) { | |||||||
|     const guessedPassword = req.body.password; |     const guessedPassword = req.body.password; | ||||||
| 
 | 
 | ||||||
|     if (verifyPassword(guessedPassword)) { |     if (verifyPassword(guessedPassword)) { | ||||||
|         const rememberMe = req.body.remember_me; |         const rememberMe = req.body.rememberMe; | ||||||
| 
 | 
 | ||||||
|         req.session.regenerate(() => { |         req.session.regenerate(() => { | ||||||
|             if (rememberMe) { |             if (rememberMe) { | ||||||
|  | |||||||
| @ -21,8 +21,8 @@ function setupPage(req, res) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // we got here because DB is not completely initialized so if schema exists
 |     // we got here because DB is not completely initialized, so if schema exists,
 | ||||||
|     // it means we're in sync in progress state.
 |     // it means we're in "sync in progress" state.
 | ||||||
|     const syncInProgress = sqlInit.schemaExists(); |     const syncInProgress = sqlInit.schemaExists(); | ||||||
| 
 | 
 | ||||||
|     if (syncInProgress) { |     if (syncInProgress) { | ||||||
|  | |||||||
| @ -215,7 +215,7 @@ function BackendScriptApi(currentNote, apiParams) { | |||||||
|      * @property {boolean} [params.isProtected=false] |      * @property {boolean} [params.isProtected=false] | ||||||
|      * @property {boolean} [params.isExpanded=false] |      * @property {boolean} [params.isExpanded=false] | ||||||
|      * @property {string} [params.prefix=''] |      * @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 |      * @returns {{note: BNote, branch: BBranch}} object contains newly created entities note and branch | ||||||
|      */ |      */ | ||||||
|     this.createNewNote = noteService.createNewNote; |     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. |      * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. | ||||||
|      * |      * | ||||||
|      * @method |      * @method | ||||||
|      * @param {integer} length of the string |      * @param {int} length of the string | ||||||
|      * @returns {string} random string |      * @returns {string} random string | ||||||
|      */ |      */ | ||||||
|     this.randomString = utils.randomString; |     this.randomString = utils.randomString; | ||||||
|  | |||||||
| @ -59,9 +59,9 @@ function cloneNoteToBranch(noteId, parentBranchId, prefix) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) { | function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) { | ||||||
|     if (isNoteDeleted(noteId)) { |     if (!(noteId in becca.notes)) { | ||||||
|         return { branch: null, success: false, message: `Note '${noteId}' is deleted.` }; |         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.` }; |         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 = {}; |     const noteIdToMeta = {}; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @param {Object.<string, integer>} existingFileNames |      * @param {Object.<string, int>} existingFileNames | ||||||
|      * @param {string} fileName |      * @param {string} fileName | ||||||
|      * @returns {string} |      * @returns {string} | ||||||
|      */ |      */ | ||||||
| @ -60,7 +60,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | |||||||
| 
 | 
 | ||||||
|             return `${index}_${fileName}`; |             return `${index}_${fileName}`; | ||||||
|         } |         } | ||||||
|         else {[] |         else { | ||||||
|             existingFileNames[lcFileName] = 1; |             existingFileNames[lcFileName] = 1; | ||||||
| 
 | 
 | ||||||
|             return fileName; |             return fileName; | ||||||
| @ -71,7 +71,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | |||||||
|      * @param {string|null} type |      * @param {string|null} type | ||||||
|      * @param {string} mime |      * @param {string} mime | ||||||
|      * @param {string} baseFileName |      * @param {string} baseFileName | ||||||
|      * @param {Object.<string, integer>} existingFileNames |      * @param {Object.<string, int>} existingFileNames | ||||||
|      * @return {string} |      * @return {string} | ||||||
|      */ |      */ | ||||||
|     function getDataFileName(type, mime, baseFileName, existingFileNames) { |     function getDataFileName(type, mime, baseFileName, existingFileNames) { | ||||||
| @ -119,7 +119,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | |||||||
|     /** |     /** | ||||||
|      * @param {BBranch} branch |      * @param {BBranch} branch | ||||||
|      * @param {NoteMeta} parentMeta |      * @param {NoteMeta} parentMeta | ||||||
|      * @param {Object.<string, integer>} existingFileNames |      * @param {Object.<string, int>} existingFileNames | ||||||
|      * @returns {NoteMeta|null} |      * @returns {NoteMeta|null} | ||||||
|      */ |      */ | ||||||
|     function createNoteMeta(branch, parentMeta, existingFileNames) { |     function createNoteMeta(branch, parentMeta, existingFileNames) { | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ class AttachmentMeta { | |||||||
|     role; |     role; | ||||||
|     /** @type {string} */ |     /** @type {string} */ | ||||||
|     mime; |     mime; | ||||||
|     /** @type {integer} */ |     /** @type {int} */ | ||||||
|     position; |     position; | ||||||
|     /** @type {string} */ |     /** @type {string} */ | ||||||
|     dataFileName; |     dataFileName; | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ class AttributeMeta { | |||||||
|     value; |     value; | ||||||
|     /** @type {boolean} */ |     /** @type {boolean} */ | ||||||
|     isInheritable; |     isInheritable; | ||||||
|     /** @type {integer} */ |     /** @type {int} */ | ||||||
|     position; |     position; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ class NoteMeta { | |||||||
|     isClone; |     isClone; | ||||||
|     /** @type {string} */ |     /** @type {string} */ | ||||||
|     title; |     title; | ||||||
|     /** @type {integer} */ |     /** @type {int} */ | ||||||
|     notePosition; |     notePosition; | ||||||
|     /** @type {string} */ |     /** @type {string} */ | ||||||
|     prefix; |     prefix; | ||||||
|  | |||||||
| @ -152,7 +152,7 @@ function getAndValidateParent(params) { | |||||||
|  * - {boolean} isProtected - default is false |  * - {boolean} isProtected - default is false | ||||||
|  * - {boolean} isExpanded - default is false |  * - {boolean} isExpanded - default is false | ||||||
|  * - {string} prefix - default is empty string |  * - {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 |  * @param params | ||||||
|  * @returns {{note: BNote, branch: BBranch}} |  * @returns {{note: BNote, branch: BBranch}} | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ function getOption(name) { | |||||||
|     return val; |     return val; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** @returns {integer} */ | /** @returns {int} */ | ||||||
| function getOptionInt(name, defaultValue = undefined) { | function getOptionInt(name, defaultValue = undefined) { | ||||||
|     const val = getOption(name); |     const val = getOption(name); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ const escape = require('escape-html'); | |||||||
| const sanitize = require("sanitize-filename"); | const sanitize = require("sanitize-filename"); | ||||||
| const mimeTypes = require('mime-types'); | const mimeTypes = require('mime-types'); | ||||||
| const path = require('path'); | const path = require('path'); | ||||||
| const log = require('./log'); |  | ||||||
| 
 | 
 | ||||||
| function newEntityId() { | function newEntityId() { | ||||||
|     return randomString(12); |     return randomString(12); | ||||||
| @ -33,11 +32,6 @@ function hashedBlobId(content) { | |||||||
|     return base64Hash.substr(0, 20); |     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) { | function toBase64(plainText) { | ||||||
|     return Buffer.from(plainText).toString('base64'); |     return Buffer.from(plainText).toString('base64'); | ||||||
| } | } | ||||||
| @ -71,30 +65,6 @@ function sanitizeSqlIdentifier(str) { | |||||||
|     return str.replace(/[^A-Za-z0-9_]/g, ""); |     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) { | function escapeHtml(str) { | ||||||
|     return escape(str); |     return escape(str); | ||||||
| } | } | ||||||
| @ -119,10 +89,6 @@ function stripTags(text) { | |||||||
|     return text.replace(/<(?:.|\n)*?>/gm, ''); |     return text.replace(/<(?:.|\n)*?>/gm, ''); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function intersection(a, b) { |  | ||||||
|     return a.filter(value => b.indexOf(value) !== -1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function union(a, b) { | function union(a, b) { | ||||||
|     const obj = {}; |     const obj = {}; | ||||||
| 
 | 
 | ||||||
| @ -231,7 +197,7 @@ function formatDownloadTitle(fileName, type, mime) { | |||||||
| 
 | 
 | ||||||
|         if (mime === 'application/octet-stream') { |         if (mime === 'application/octet-stream') { | ||||||
|             // we didn't find any good guess for this one, it will be better to just return
 |             // 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
 |             // extension too
 | ||||||
| 
 | 
 | ||||||
|             return fileName; |             return fileName; | ||||||
| @ -318,10 +284,6 @@ function normalize(str) { | |||||||
|     return removeDiacritic(str).toLowerCase(); |     return removeDiacritic(str).toLowerCase(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function filterAttributeName(name) { |  | ||||||
|     return name.replace(/[^\p{L}\p{N}_:]/ug, ""); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     randomSecureToken, |     randomSecureToken, | ||||||
|     randomString, |     randomString, | ||||||
| @ -334,17 +296,13 @@ module.exports = { | |||||||
|     hash, |     hash, | ||||||
|     isEmptyOrWhitespace, |     isEmptyOrWhitespace, | ||||||
|     sanitizeSqlIdentifier, |     sanitizeSqlIdentifier, | ||||||
|     prepareSqlForLike, |  | ||||||
|     stopWatch, |  | ||||||
|     escapeHtml, |     escapeHtml, | ||||||
|     unescapeHtml, |     unescapeHtml, | ||||||
|     toObject, |     toObject, | ||||||
|     stripTags, |     stripTags, | ||||||
|     intersection, |  | ||||||
|     union, |     union, | ||||||
|     escapeRegExp, |     escapeRegExp, | ||||||
|     crash, |     crash, | ||||||
|     sanitizeFilenameForHeader, |  | ||||||
|     getContentDisposition, |     getContentDisposition, | ||||||
|     isStringNote, |     isStringNote, | ||||||
|     quoteRegex, |     quoteRegex, | ||||||
| @ -356,7 +314,5 @@ module.exports = { | |||||||
|     deferred, |     deferred, | ||||||
|     removeDiacritic, |     removeDiacritic, | ||||||
|     normalize, |     normalize, | ||||||
|     filterAttributeName, |  | ||||||
|     hashedBlobId, |     hashedBlobId, | ||||||
|     randomBlobId |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ class SAttribute extends AbstractShacaEntity { | |||||||
|         this.type = type; |         this.type = type; | ||||||
|         /** @param {string} */ |         /** @param {string} */ | ||||||
|         this.name = name; |         this.name = name; | ||||||
|         /** @param {integer} */ |         /** @param {int} */ | ||||||
|         this.position = position; |         this.position = position; | ||||||
|         /** @param {string} */ |         /** @param {string} */ | ||||||
|         this.value = value; |         this.value = value; | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ class Shaca { | |||||||
|         this.attributes = {}; |         this.attributes = {}; | ||||||
|         /** @type {Object.<String, SAttachment>} */ |         /** @type {Object.<String, SAttachment>} */ | ||||||
|         this.attachments = {}; |         this.attachments = {}; | ||||||
|         /** @type {Object.<String, String>} */ |         /** @type {Object.<String, SNote>} */ | ||||||
|         this.aliasToNote = {}; |         this.aliasToNote = {}; | ||||||
| 
 | 
 | ||||||
|         /** @type {SNote|null} */ |         /** @type {SNote|null} */ | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ | |||||||
|             <div class="form-group"> |             <div class="form-group"> | ||||||
|                 <div class="checkbox"> |                 <div class="checkbox"> | ||||||
|                     <label> |                     <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> |                     </label> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam