Use localforage to work around private browsing issues

Related #159
This commit is contained in:
Nils Maier 2020-08-29 22:55:32 +02:00
parent 1af01856e1
commit 6282f54ac0
5 changed files with 63 additions and 77 deletions

View File

@ -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<string, string>(
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<string>(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<Localization> {
}
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<string>(CUSTOM_KEY);
if (custom) {
try {
valid.push(JSON.parse(custom));
@ -302,11 +304,11 @@ export async function localize<T extends HTMLElement | DocumentFragment>(
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);
}

View File

@ -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<string, string>([
]));
export const IconCache = new class IconCache extends EventEmitter {
private db: Promise<IDBDatabase>;
private db = lf.createInstance({name: STORE});
private cache: Map<string, string>;
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<IDBDatabase>((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<string | undefined>(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<any>(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);
}
}();

View File

@ -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"

View File

@ -641,10 +641,11 @@ addEventListener("DOMContentLoaded", async () => {
$<HTMLInputElement>("#loadCustomLocale").addEventListener("click", () => {
customLocale.click();
});
$<HTMLInputElement>("#clearCustomLocale").addEventListener("click", () => {
saveCustomLocale(undefined);
runtime.reload();
});
$<HTMLInputElement>("#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();
}

View File

@ -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"