/* This file is part of the Notesnook project (https://notesnook.com/) Copyright (C) 2023 Streetwriters (Private) Limited This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* * Only WOFF and EOT mime types for fonts are 'real' * see http://www.iana.org/assignments/media-types/media-types.xhtml */ const WOFF = "application/font-woff"; const JPEG = "image/jpeg"; const mimes = { woff: WOFF, woff2: WOFF, ttf: "application/font-truetype", eot: "application/vnd.ms-fontobject", png: "image/png", jpg: JPEG, jpeg: JPEG, gif: "image/gif", tiff: "image/tiff", svg: "image/svg+xml" }; function parseExtension(url: string) { const match = /\.([^./]*?)(\?|$)/g.exec(url); if (match) return match[1]; else return ""; } function mimeType(url: string) { const extension = parseExtension(url).toLowerCase(); return mimes[extension as keyof typeof mimes] || ""; } function isDataUrl(url: string) { return url.search(/^(data:)/) !== -1; } function asBlob(canvas: HTMLCanvasElement) { const binaryString = atob(canvas.toDataURL().split(",")[1]); const length = binaryString.length; const binaryArray = new Uint8Array(length); for (let i = 0; i < length; i++) binaryArray[i] = binaryString.charCodeAt(i); return new Blob([binaryArray], { type: "image/png" }); } function canvasToBlob(canvas: HTMLCanvasElement) { if (canvas.toBlob) return new Promise(function (resolve) { canvas.toBlob(resolve); }); return Promise.resolve(asBlob(canvas)); } function resolveUrl(url: string, baseUrl: string) { const doc = document.implementation.createHTMLDocument(); const base = doc.createElement("base"); doc.head.appendChild(base); const a = doc.createElement("a"); doc.body.appendChild(a); base.href = baseUrl; a.href = url; return a.href; } let index = 0; function uid() { return "u" + fourRandomChars() + index++; function fourRandomChars() { /* see http://stackoverflow.com/a/6248722/2519373 */ return ( "0000" + ((Math.random() * Math.pow(36, 4)) << 0).toString(36) ).slice(-4); } } function dataAsUrl(content: string, type: string) { return "data:" + type + ";base64," + content; } function escape(string: string) { return string.replace(/([.*+?^${}()|[\]/\\])/g, "\\$1"); } function delay(ms: number) { return function (arg: T) { return new Promise(function (resolve) { setTimeout(function () { resolve(arg); }, ms); }); }; } function asArray(arrayLike: ArrayLike) { const array = []; const length = arrayLike.length; for (let i = 0; i < length; i++) array.push(arrayLike[i]); return array; } function escapeXhtml(string: string) { return string.replace(/%/g, "%25").replace(/#/g, "%23").replace(/\n/g, "%0A"); } function width(node: HTMLElement) { const leftBorder = px(node, "border-left-width"); const rightBorder = px(node, "border-right-width"); return node.scrollWidth + leftBorder + rightBorder; } function height(node: HTMLElement) { const topBorder = px(node, "border-top-width"); const bottomBorder = px(node, "border-bottom-width"); return node.scrollHeight + topBorder + bottomBorder; } function px(node: HTMLElement, styleProperty: string) { const value = getComputedStyle(node).getPropertyValue(styleProperty); return parseFloat(value.replace("px", "")); } function injectCss(rules: string, id: string) { const variableCss = document.getElementById(id); const head = document.getElementsByTagName("head")[0]; if (variableCss) { head.removeChild(variableCss); } const css = document.createElement("style"); css.type = "text/css"; css.id = id; css.appendChild(document.createTextNode(rules)); head.insertBefore(css, getRootStylesheet()); } function getRootStylesheet() { for (const sty of document.querySelectorAll("style")) { if (sty.innerHTML.includes("#root")) { return sty; } } return null; } const SVGElements = [ "altGlyph", "altGlyphDef", "altGlyphItem", "animate", "animateColor", "animateMotion", "animateTransform", "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "ellipse", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignObject", "g", "glyph", "glyphRef", "hkern", "image", "line", "linearGradient", "marker", "mask", "metadata", "missing-glyph", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "set", "stop", "svg", "switch", "symbol", "text", "textPath", "title", "tref", "tspan", "use", "view", "vkern" ].map((a) => a.toLowerCase()); function isSVGElement(element: HTMLElement) { if (!element || !element.tagName) return false; return SVGElements.includes(element.tagName.toLowerCase()); } export { injectCss, escape, parseExtension, mimeType, dataAsUrl, isDataUrl, canvasToBlob, resolveUrl, uid, delay, asArray, escapeXhtml, width, height, isSVGElement };