diff --git a/lib/i18n.ts b/lib/i18n.ts index 35a07b9..7a734e4 100644 --- a/lib/i18n.ts +++ b/lib/i18n.ts @@ -4,7 +4,7 @@ import {memoize} from "./memoize"; import langs from "../_locales/all.json"; import { sorted, naturalCaseCompare } from "./sorting"; - +import lf from "localforage"; export const ALL_LANGS = Object.freeze(new Map( sorted(Object.entries(langs), e => { @@ -123,14 +123,16 @@ async function fetchLanguage(code: string) { } -function loadCached() { - if (document.location.pathname.includes("/windows/")) { - const cached = localStorage.getItem(CACHE_KEY); - if (cached) { - return JSON.parse(cached) as any[]; - } +async function loadCached() { + const cached = await lf.getItem(CACHE_KEY); + if (!cached) { + return null; } - return null; + const parsed = JSON.parse(cached); + if (Array.isArray(parsed)) { + return null; + } + return parsed; } async function loadRawLocales() { @@ -187,16 +189,16 @@ async function load(): Promise { } CURRENT = currentLang; // en is the base locale - let valid = loadCached(); + let valid = await loadCached(); if (!valid) { valid = await loadRawLocales(); - localStorage.setItem(CACHE_KEY, JSON.stringify(valid)); + await lf.setItem(CACHE_KEY, JSON.stringify(valid)); } if (!valid.length) { throw new Error("Could not lood ANY of these locales"); } - const custom = localStorage.getItem(CUSTOM_KEY); + const custom = await lf.getItem(CUSTOM_KEY); if (custom) { try { valid.push(JSON.parse(custom)); @@ -302,11 +304,11 @@ export async function localize( return localize_(elem); } -export function saveCustomLocale(data?: string) { +export async function saveCustomLocale(data?: string) { if (!data) { - localStorage.removeItem(CUSTOM_KEY); + await lf.removeItem(CUSTOM_KEY); return; } new Localization(JSON.parse(data)); - localStorage.setItem(CUSTOM_KEY, data); + await localStorage.setItem(CUSTOM_KEY, data); } diff --git a/lib/iconcache.ts b/lib/iconcache.ts index 2f02041..e79dcd7 100644 --- a/lib/iconcache.ts +++ b/lib/iconcache.ts @@ -4,9 +4,11 @@ import { downloads, CHROME } from "./browser"; import { EventEmitter } from "../uikit/lib/events"; import { PromiseSerializer } from "./pserializer"; +import lf from "localforage"; + -const VERSION = 1; const STORE = "iconcache"; + // eslint-disable-next-line no-magic-numbers const CACHE_SIZES = CHROME ? [16, 32] : [16, 32, 64, 127]; @@ -48,37 +50,17 @@ const SYNONYMS = Object.freeze(new Map([ ])); export const IconCache = new class IconCache extends EventEmitter { - private db: Promise; + private db = lf.createInstance({name: STORE}); private cache: Map; constructor() { super(); - this.db = this.init(); this.cache = new Map(); this.get = PromiseSerializer.wrapNew(8, this, this.get); this.set = PromiseSerializer.wrapNew(1, this, this.set); } - private async init() { - return await new Promise((resolve, reject) => { - const req = indexedDB.open(STORE, VERSION); - req.onupgradeneeded = evt => { - const db = req.result; - switch (evt.oldVersion) { - case 0: { - db.createObjectStore(STORE); - break; - } - } - }; - req.onerror = ex => reject(ex); - req.onsuccess = () => { - resolve(req.result); - }; - }); - } - private normalize(ext: string) { ext = ext.toLocaleLowerCase(); return SYNONYMS.get(ext) || ext; @@ -95,36 +77,25 @@ export const IconCache = new class IconCache extends EventEmitter { if (rv) { return rv; } - const db = await this.db; rv = this.cache.get(sext); if (rv) { return rv; } - return await new Promise(resolve => { - const trans = db.transaction(STORE, "readonly"); - trans.onerror = () => resolve(undefined); - const store = trans.objectStore(STORE); - const req = store.get(sext); - req.onerror = () => resolve(undefined); - req.onsuccess = () => { - const rv = this.cache.get(sext); - if (rv) { - resolve(rv); - return; - } - let {result} = req; - if (!result) { - resolve(undefined); - return; - } - if (typeof req.result !== "string") { - result = URL.createObjectURL(result).toString(); - } - this.cache.set(sext, result); - this.cache.set(ext, ""); - resolve(result); - }; - }); + let result = await this.db.getItem(sext); + if (!result) { + return this.cache.get(sext); + } + rv = this.cache.get(sext); + if (rv) { + return rv; + } + if (typeof result !== "string") { + result = URL.createObjectURL(result).toString(); + } + + this.cache.set(sext, result); + this.cache.set(ext, ""); + return result; } async set(ext: string, manId: number) { @@ -145,18 +116,9 @@ export const IconCache = new class IconCache extends EventEmitter { } for (const {size, icon} of urls) { this.cache.set(`${ext}-${size}`, URL.createObjectURL(icon)); + await this.db.setItem(`${ext}-${size}`, icon); } this.cache.set(ext, ""); - const db = await this.db; - await new Promise((resolve, reject) => { - const trans = db.transaction(STORE, "readwrite"); - trans.onerror = reject; - trans.oncomplete = resolve; - const store = trans.objectStore(STORE); - for (const {size, icon} of urls) { - store.put(icon, `${ext}-${size}`); - } - }); this.emit("cached", ext); } }(); diff --git a/package.json b/package.json index 843c4b9..57d17e9 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "dependencies": { "@types/psl": "^1.1.0", "@types/whatwg-mimetype": "^2.1.0", + "localforage": "^1.9.0", "psl": "^1.4.0", "webextension-polyfill": "^0.5.0", "whatwg-mimetype": "^2.3.0" diff --git a/windows/prefs.ts b/windows/prefs.ts index 5b58970..3ca7126 100644 --- a/windows/prefs.ts +++ b/windows/prefs.ts @@ -641,10 +641,11 @@ addEventListener("DOMContentLoaded", async () => { $("#loadCustomLocale").addEventListener("click", () => { customLocale.click(); }); - $("#clearCustomLocale").addEventListener("click", () => { - saveCustomLocale(undefined); - runtime.reload(); - }); + $("#clearCustomLocale"). + addEventListener("click", async () => { + await saveCustomLocale(undefined); + runtime.reload(); + }); customLocale.addEventListener("change", async () => { if (!customLocale.files || !customLocale.files.length) { return; @@ -662,7 +663,8 @@ addEventListener("DOMContentLoaded", async () => { reader.onerror = reject; reader.readAsText(file); }); - saveCustomLocale(text); + await saveCustomLocale(text); + if (confirm("Imported your file.\nWant to relaod the extension now?")) { runtime.reload(); } diff --git a/yarn.lock b/yarn.lock index 7c22b2e..06a0ae5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1745,6 +1745,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + import-fresh@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" @@ -2084,6 +2089,13 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" @@ -2098,6 +2110,13 @@ loader-utils@^1.0.2, loader-utils@^1.2.3, loader-utils@^1.4.0: emojis-list "^3.0.0" json5 "^1.0.1" +localforage@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1" + integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g== + dependencies: + lie "3.1.1" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"