zotero-better-notes/src/utils/str.ts

149 lines
3.6 KiB
TypeScript

import seedrandom = require("seedrandom");
import pathHelper = require("path-browserify");
export function slice(str: string, len: number) {
return str.length > len ? `${str.slice(0, len - 3)}...` : str;
}
export function fill(
str: string,
len: number,
options: { char: string; position: "start" | "end" } = {
char: " ",
position: "end",
},
) {
if (str.length >= len) {
return str;
}
return str[options.position === "start" ? "padStart" : "padEnd"](
len - str.length,
options.char,
);
}
export function formatPath(path: string, suffix: string = "") {
path = Zotero.File.normalizeToUnix(path);
if (Zotero.isWin) {
path = path.replace(/\//g, "\\");
}
if (suffix && !path.endsWith(suffix)) {
path += suffix;
}
return path;
}
export async function getFileContent(path: string) {
const contentOrXHR = await Zotero.File.getContentsAsync(path);
const content =
typeof contentOrXHR === "string"
? contentOrXHR
: (contentOrXHR as any as XMLHttpRequest).response;
return content;
}
export function randomString(len: number, seed?: string, chars?: string) {
if (!chars) {
chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
}
if (!len) {
len = 8;
}
let str = "";
const random = seedrandom(seed);
for (let i = 0; i < len; i++) {
const rnum = Math.floor(random() * chars.length);
str += chars.substring(rnum, rnum + 1);
}
return str;
}
function arrayBufferToBase64(buffer: ArrayBufferLike) {
let binary = "";
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return ztoolkit.getGlobal("btoa")(binary);
}
export async function getItemDataURL(item: Zotero.Item) {
if (addon.data.imageCache[item.id]) {
return addon.data.imageCache[item.id];
}
const path = (await item.getFilePathAsync()) as string;
const buf = (await IOUtils.read(path)).buffer;
const dataURL =
"data:" +
item.attachmentContentType +
";base64," +
arrayBufferToBase64(buf);
const keys = Object.keys(addon.data.imageCache);
// Limit cache size
while (keys.length > 100) {
delete addon.data.imageCache[keys.shift() as any];
}
addon.data.imageCache[item.id] = dataURL;
return dataURL;
}
export async function fileExists(path: string): Promise<boolean> {
if (!path) {
return false;
}
try {
// IOUtils.exists() will throw error if path is not valid
return await IOUtils.exists(formatPath(path));
} catch (e) {
ztoolkit.log("[fileExists]", e);
return false;
}
}
export function jointPath(...paths: string[]) {
try {
return formatPath(
pathHelper.join(...paths.map((p) => p.replaceAll("\\", "/"))),
);
} catch (e) {
ztoolkit.log("[jointPath]", e);
return "";
}
}
export function tryDecodeParse(s: string) {
try {
return JSON.parse(decodeURIComponent(s));
} catch (e) {
return null;
}
}
export function htmlEscape(doc: Document, str: string) {
const div = doc.createElement("div");
const text = doc.createTextNode(str);
div.appendChild(text);
return div.innerHTML.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
}
export function htmlUnescape(
str: string,
options: {
excludeLineBreak?: boolean;
} = {},
) {
const map: Record<string, string> = {
"&nbsp;": " ",
"&quot;": '"',
"&#39;": "'",
};
if (!options.excludeLineBreak) {
map["\n"] = "";
}
const re = new RegExp(Object.keys(map).join("|"), "g");
return str.replace(re, function (match) {
return map[match as keyof typeof map];
});
}