diff --git a/apps/client/src/services/toast.ts b/apps/client/src/services/toast.ts index f31e242cd..b67c89eb2 100644 --- a/apps/client/src/services/toast.ts +++ b/apps/client/src/services/toast.ts @@ -3,7 +3,7 @@ import { signal } from "@preact/signals"; import appContext from "../components/app_context.js"; import froca from "./froca.js"; import { t } from "./i18n.js"; -import utils from "./utils.js"; +import utils, { randomString } from "./utils.js"; export interface ToastOptions { id?: string; @@ -86,7 +86,7 @@ export async function showErrorForScriptNote(noteId: string, message: string) { export const toasts = signal([]); function addToast(opts: ToastOptions) { - const id = opts.id ?? crypto.randomUUID(); + const id = opts.id ?? randomString(); const toast = { ...opts, id }; toasts.value = [ ...toasts.value, toast ]; return id; diff --git a/apps/client/src/services/utils.ts b/apps/client/src/services/utils.ts index 8c2a12c6a..9dff8fef2 100644 --- a/apps/client/src/services/utils.ts +++ b/apps/client/src/services/utils.ts @@ -1,8 +1,9 @@ import { dayjs } from "@triliumnext/commons"; -import type { ViewMode, ViewScope } from "./link.js"; -import FNote from "../entities/fnote"; import { snapdom } from "@zumer/snapdom"; +import FNote from "../entities/fnote"; +import type { ViewMode, ViewScope } from "./link.js"; + const SVG_MIME = "image/svg+xml"; export const isShare = !window.glob; @@ -113,9 +114,8 @@ function formatDateISO(date: Date) { export function formatDateTime(date: Date, userSuppliedFormat?: string): string { if (userSuppliedFormat?.trim()) { return dayjs(date).format(userSuppliedFormat); - } else { - return `${formatDate(date)} ${formatTime(date)}`; } + return `${formatDate(date)} ${formatTime(date)}`; } function localNowDateTime() { @@ -191,9 +191,9 @@ export function formatSize(size: number | null | undefined) { if (size < 1024) { return `${size} KiB`; - } else { - return `${Math.round(size / 102.4) / 10} MiB`; } + return `${Math.round(size / 102.4) / 10} MiB`; + } function toObject(array: T[], fn: (arg0: T) => [key: string, value: R]) { @@ -208,7 +208,7 @@ function toObject(array: T[], fn: (arg0: T) => [key: string, value: R]) { return obj; } -export function randomString(len: number) { +export function randomString(len: number = 16) { let text = ""; const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -297,18 +297,18 @@ function formatHtml(html: string) { let indent = "\n"; const tab = "\t"; let i = 0; - let pre: { indent: string; tag: string }[] = []; + const pre: { indent: string; tag: string }[] = []; html = html - .replace(new RegExp("
([\\s\\S]+?)?
"), function (x) { + .replace(new RegExp("
([\\s\\S]+?)?
"), (x) => { pre.push({ indent: "", tag: x }); - return "<--TEMPPRE" + i++ + "/-->"; + return `<--TEMPPRE${i++}/-->`; }) - .replace(new RegExp("<[^<>]+>[^<]?", "g"), function (x) { + .replace(new RegExp("<[^<>]+>[^<]?", "g"), (x) => { let ret; const tagRegEx = /<\/?([^\s/>]+)/.exec(x); - let tag = tagRegEx ? tagRegEx[1] : ""; - let p = new RegExp("<--TEMPPRE(\\d+)/-->").exec(x); + const tag = tagRegEx ? tagRegEx[1] : ""; + const p = new RegExp("<--TEMPPRE(\\d+)/-->").exec(x); if (p) { const pInd = parseInt(p[1]); @@ -318,24 +318,22 @@ function formatHtml(html: string) { if (["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"].indexOf(tag) >= 0) { // self closing tag ret = indent + x; + } else if (x.indexOf("") ret = indent + x.substr(0, x.length - 1) + indent + tab + x.substr(x.length - 1, x.length); + else ret = indent + x; + !p && (indent += tab); } else { - if (x.indexOf("") ret = indent + x.substr(0, x.length - 1) + indent + tab + x.substr(x.length - 1, x.length); - else ret = indent + x; - !p && (indent += tab); - } else { - //close tag - indent = indent.substr(0, indent.length - 1); - if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + x.substr(x.length - 1, x.length); - else ret = indent + x; - } + //close tag + indent = indent.substr(0, indent.length - 1); + if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + x.substr(x.length - 1, x.length); + else ret = indent + x; } return ret; }); for (i = pre.length; i--;) { - html = html.replace("<--TEMPPRE" + i + "/-->", pre[i].tag.replace("
", "
\n").replace("
", pre[i].indent + "
")); + html = html.replace(`<--TEMPPRE${i}/-->`, pre[i].tag.replace("
", "
\n").replace("
", `${pre[i].indent}
`)); } return html.charAt(0) === "\n" ? html.substr(1, html.length - 1) : html; @@ -364,11 +362,11 @@ type dynamicRequireMappings = { export function dynamicRequire(moduleName: T): Awaited{ if (typeof __non_webpack_require__ !== "undefined") { return __non_webpack_require__(moduleName); - } else { - // explicitly pass as string and not as expression to suppress webpack warning - // 'Critical dependency: the request of a dependency is an expression' - return require(`${moduleName}`); } + // explicitly pass as string and not as expression to suppress webpack warning + // 'Critical dependency: the request of a dependency is an expression' + return require(`${moduleName}`); + } function timeLimit(promise: Promise, limitMs: number, errorMessage?: string) { @@ -509,8 +507,8 @@ export function escapeRegExp(str: string) { function areObjectsEqual(...args: unknown[]) { let i; let l; - let leftChain: Object[]; - let rightChain: Object[]; + let leftChain: object[]; + let rightChain: object[]; function compare2Objects(x: unknown, y: unknown) { let p; @@ -695,9 +693,9 @@ async function downloadAsSvg(nameWithoutExtension: string, svgSource: string | S try { const result = await snapdom(element, { - backgroundColor: "transparent", - scale: 2 - }); + backgroundColor: "transparent", + scale: 2 + }); triggerDownload(`${nameWithoutExtension}.svg`, result.url); } finally { cleanup(); @@ -733,9 +731,9 @@ async function downloadAsPng(nameWithoutExtension: string, svgSource: string | S try { const result = await snapdom(element, { - backgroundColor: "transparent", - scale: 2 - }); + backgroundColor: "transparent", + scale: 2 + }); const pngImg = await result.toPng(); await triggerDownload(`${nameWithoutExtension}.png`, pngImg.src); } finally { @@ -763,11 +761,11 @@ export function getSizeFromSvg(svgContent: string) { return { width: parseFloat(width), height: parseFloat(height) - } - } else { - console.warn("SVG export error", svgDocument.documentElement); - return null; + }; } + console.warn("SVG export error", svgDocument.documentElement); + return null; + } /** @@ -896,9 +894,9 @@ export function mapToKeyValueArray(map: R export function getErrorMessage(e: unknown) { if (e && typeof e === "object" && "message" in e && typeof e.message === "string") { return e.message; - } else { - return "Unknown error"; } + return "Unknown error"; + } /** diff --git a/apps/client/src/widgets/PromotedAttributes.tsx b/apps/client/src/widgets/PromotedAttributes.tsx index 33997949b..0ec79725a 100644 --- a/apps/client/src/widgets/PromotedAttributes.tsx +++ b/apps/client/src/widgets/PromotedAttributes.tsx @@ -13,6 +13,7 @@ import debounce from "../services/debounce"; import { t } from "../services/i18n"; import { DefinitionObject, extractAttributeDefinitionTypeAndName, LabelType } from "../services/promoted_attribute_definition_parser"; import server from "../services/server"; +import { randomString } from "../services/utils"; import ws from "../services/ws"; import { useNoteContext, useNoteLabel, useTriliumEvent, useUniqueName } from "./react/hooks"; import NoteAutocomplete from "./react/NoteAutocomplete"; @@ -116,7 +117,7 @@ export function usePromotedAttributeData(note: FNote | null | undefined, compone valueAttr.attributeId = ""; } - const uniqueId = crypto.randomUUID(); + const uniqueId = randomString(); cells.push({ definitionAttr, definition, valueAttr, valueName, uniqueId }); } } @@ -319,7 +320,7 @@ function MultiplicityCell({ cell, cells, setCells, setCellToFocus, note, compone const index = cells.indexOf(cell); const newCell: Cell = { ...cell, - uniqueId: crypto.randomUUID(), + uniqueId: randomString(), valueAttr: { attributeId: "", type: cell.valueAttr.type, diff --git a/apps/client/src/widgets/basic_widget.ts b/apps/client/src/widgets/basic_widget.ts index eb6b55b0d..0d515b38a 100644 --- a/apps/client/src/widgets/basic_widget.ts +++ b/apps/client/src/widgets/basic_widget.ts @@ -4,6 +4,7 @@ import Component, { TypedComponent } from "../components/component.js"; import froca from "../services/froca.js"; import { t } from "../services/i18n.js"; import toastService, { showErrorForScriptNote } from "../services/toast.js"; +import { randomString } from "../services/utils.js"; import { renderReactWidget } from "./react/react_utils.jsx"; export class TypedBasicWidget> extends TypedComponent { @@ -180,7 +181,7 @@ export class TypedBasicWidget> extends TypedCompon }); } else { toastService.showPersistent({ - id: `custom-widget-failure-unknown-${crypto.randomUUID()}`, + id: `custom-widget-failure-unknown-${randomString()}`, title: t("toast.widget-error.title"), icon: "bx bx-error-circle", message: t("toast.widget-error.message-unknown", { diff --git a/apps/client/src/widgets/sidebar/HighlightsList.tsx b/apps/client/src/widgets/sidebar/HighlightsList.tsx index 66249f329..401554203 100644 --- a/apps/client/src/widgets/sidebar/HighlightsList.tsx +++ b/apps/client/src/widgets/sidebar/HighlightsList.tsx @@ -3,6 +3,7 @@ import { createPortal } from "preact/compat"; import { useCallback, useEffect, useState } from "preact/hooks"; import { t } from "../../services/i18n"; +import { randomString } from "../../services/utils"; import { useActiveNoteContext, useContentElement, useIsNoteReadOnly, useNoteProperty, useTextEditor, useTriliumOptionJson } from "../react/hooks"; import Modal from "../react/Modal"; import { HighlightsListOptions } from "../type_widgets/options/text_notes"; @@ -201,7 +202,7 @@ function extractHighlightsFromTextEditor(editor: CKTextEditor) { if (Object.values(attrs).some(Boolean)) { result.push({ - id: crypto.randomUUID(), + id: randomString(), text: item.data, attrs, textNode: item.textNode, @@ -269,7 +270,7 @@ function extractHighlightsFromStaticHtml(el: HTMLElement | null) { if (Object.values(attrs).some(Boolean)) { highlights.push({ - id: crypto.randomUUID(), + id: randomString(), text: node.textContent, element: el, attrs diff --git a/apps/client/src/widgets/sidebar/TableOfContents.tsx b/apps/client/src/widgets/sidebar/TableOfContents.tsx index 06eb2fff8..44a912af0 100644 --- a/apps/client/src/widgets/sidebar/TableOfContents.tsx +++ b/apps/client/src/widgets/sidebar/TableOfContents.tsx @@ -5,6 +5,7 @@ import clsx from "clsx"; import { useCallback, useEffect, useState } from "preact/hooks"; import { t } from "../../services/i18n"; +import { randomString } from "../../services/utils"; import { useActiveNoteContext, useContentElement, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks"; import Icon from "../react/Icon"; import RightPanelWidget from "./RightPanelWidget"; @@ -172,7 +173,7 @@ function extractTocFromTextEditor(editor: CKTextEditor) { // Assign a unique ID let tocId = item.getAttribute(TOC_ID) as string | undefined; if (!tocId) { - tocId = crypto.randomUUID(); + tocId = randomString(); writer.setAttribute(TOC_ID, tocId, item); } @@ -210,7 +211,7 @@ function extractTocFromStaticHtml(el: HTMLElement | null) { const headings: DomHeading[] = []; for (const headingEl of el.querySelectorAll("h1,h2,h3,h4,h5,h6")) { headings.push({ - id: crypto.randomUUID(), + id: randomString(), level: parseInt(headingEl.tagName.substring(1), 10), text: headingEl.textContent, element: headingEl