mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02: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">
|
||||||
|
@ -84,15 +84,11 @@ export default class TocWidget extends RightPanelWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async refreshWithNote(note) {
|
async refreshWithNote(note) {
|
||||||
/*The reason for adding tocPreviousVisible is to record whether the previous state of the toc is hidden or displayed,
|
/*The reason for adding tocPreviousVisible is to record whether the previous state of the toc is hidden or displayed,
|
||||||
* 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');
|
||||||
|
|
||||||
@ -112,10 +108,10 @@ export default class TocWidget extends RightPanelWidget {
|
|||||||
this.$toc.html($toc);
|
this.$toc.html($toc);
|
||||||
if (["", "show"].includes(tocLabel?.value) || headingCount >= options.getInt('minTocHeadings')){
|
if (["", "show"].includes(tocLabel?.value) || headingCount >= options.getInt('minTocHeadings')){
|
||||||
this.toggleInt(true);
|
this.toggleInt(true);
|
||||||
this.noteContext.viewScope.tocPreviousVisible=true;
|
this.noteContext.viewScope.tocPreviousVisible=true;
|
||||||
}else{
|
}else{
|
||||||
this.toggleInt(false);
|
this.toggleInt(false);
|
||||||
this.noteContext.viewScope.tocPreviousVisible=false;
|
this.noteContext.viewScope.tocPreviousVisible=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.triggerCommand("reEvaluateRightPaneVisibility");
|
this.triggerCommand("reEvaluateRightPaneVisibility");
|
||||||
|
@ -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