diff --git a/background/background.js b/background/background.js index d90a63be..b1c1c20d 100644 --- a/background/background.js +++ b/background/background.js @@ -135,24 +135,13 @@ if (chrome.commands) { // ************************************************************************* chrome.runtime.onInstalled.addListener(({reason, previousVersion}) => { - // save install type: "admin", "development", "normal", "sideload" or "other" - // "normal" = addon installed from webstore - chrome.management.getSelf(info => { - localStorage.installType = info.installType; - if (reason === 'install' && info.installType === 'development' && chrome.contextMenus) { - createContextMenus(['reload']); - } - }); - if (reason !== 'update') return; - // translations may change - localStorage.L10N = JSON.stringify({ - browserUIlanguage: chrome.i18n.getUILanguage(), - }); - // themes may change - delete localStorage.codeMirrorThemes; - // inline search cache for USO is not needed anymore, TODO: remove this by the middle of 2021 if (semverCompare(previousVersion, '1.5.13') <= 0) { + // Removing unused stuff + // TODO: delete this entire block by the middle of 2021 + try { + localStorage.clear(); + } catch (e) {} setTimeout(async () => { const del = Object.keys(await chromeLocal.get()) .filter(key => key.startsWith('usoSearchCache')); @@ -181,7 +170,7 @@ contextMenus = { click: browserCommands.openOptions, }, 'reload': { - presentIf: () => localStorage.installType === 'development', + presentIf: async () => (await browser.management.getSelf()).installType === 'development', title: 'reload', click: browserCommands.reload, }, @@ -198,10 +187,10 @@ contextMenus = { } }; -function createContextMenus(ids) { +async function createContextMenus(ids) { for (const id of ids) { let item = contextMenus[id]; - if (item.presentIf && !item.presentIf()) { + if (item.presentIf && !await item.presentIf()) { continue; } item = Object.assign({id}, item); diff --git a/background/db.js b/background/db.js index 223d3870..84075e18 100644 --- a/background/db.js +++ b/background/db.js @@ -24,14 +24,11 @@ const db = (() => { async function tryUsingIndexedDB() { // we use chrome.storage.local fallback if IndexedDB doesn't save data, // which, once detected on the first run, is remembered in chrome.storage.local - // for reliablility and in localStorage for fast synchronous access - // (FF may block localStorage depending on its privacy options) - // note that it may throw when accessing the variable - // https://github.com/openstyles/stylus/issues/615 + // note that accessing indexedDB may throw, https://github.com/openstyles/stylus/issues/615 if (typeof indexedDB === 'undefined') { throw new Error('indexedDB is undefined'); } - switch (await getFallback()) { + switch (await chromeLocal.getValue(FALLBACK)) { case true: throw null; case false: break; default: await testDB(); @@ -39,12 +36,6 @@ const db = (() => { return useIndexedDB(); } - async function getFallback() { - return localStorage[FALLBACK] === 'true' ? true : - localStorage[FALLBACK] === 'false' ? false : - chromeLocal.getValue(FALLBACK); - } - async function testDB() { let e = await dbExecIndexedDB('getAllKeys', IDBKeyRange.lowerBound(1), 1); // throws if result is null @@ -62,13 +53,11 @@ const db = (() => { chromeLocal.setValue(FALLBACK + 'Reason', workerUtil.cloneError(err)); console.warn('Failed to access indexedDB. Switched to storage API.', err); } - localStorage[FALLBACK] = 'true'; return createChromeStorageDB().exec; } function useIndexedDB() { chromeLocal.setValue(FALLBACK, false); - localStorage[FALLBACK] = 'false'; return dbExecIndexedDB; } diff --git a/background/update.js b/background/update.js index ec55a9e5..9b877cbd 100644 --- a/background/update.js +++ b/background/update.js @@ -35,7 +35,7 @@ const ALARM_NAME = 'scheduledUpdate'; const MIN_INTERVAL_MS = 60e3; - let lastUpdateTime = parseInt(localStorage.lastUpdateTime) || Date.now(); + let lastUpdateTime; let checkingAll = false; let logQueue = []; let logLastWriteTime = 0; @@ -46,9 +46,11 @@ API_METHODS.updateCheck = checkStyle; API_METHODS.getUpdaterStates = () => STATES; - prefs.subscribe(['updateInterval'], schedule); - schedule(); - chrome.alarms.onAlarm.addListener(onAlarm); + chromeLocal.getValue('lastUpdateTime').then(val => { + lastUpdateTime = val || Date.now(); + prefs.subscribe('updateInterval', schedule, {now: true}); + chrome.alarms.onAlarm.addListener(onAlarm); + }); return {checkAllStyles, checkStyle, STATES}; @@ -255,7 +257,7 @@ } function resetInterval() { - localStorage.lastUpdateTime = lastUpdateTime = Date.now(); + chromeLocal.setValue('lastUpdateTime', lastUpdateTime = Date.now()); schedule(); } diff --git a/edit/edit.js b/edit/edit.js index c1de3dd0..02755ce9 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -22,7 +22,7 @@ prefs rerouteHotkeys SectionsEditor - sessionStorageHash + sessionStore setupLivePrefs SourceEditor t @@ -100,7 +100,7 @@ lazyInit(); // switching the mode here to show the correct page ASAP, usually before DOMContentLoaded editor.isUsercss = Boolean(style.usercssData || !style.id && prefs.get('newStyleAsUsercss')); document.documentElement.classList.toggle('usercss', editor.isUsercss); - sessionStorage.justEditedStyleId = style.id || ''; + sessionStore.justEditedStyleId = style.id || ''; // no such style so let's clear the invalid URL parameters if (!style.id) history.replaceState({}, '', location.pathname); updateTitle(false); @@ -335,7 +335,7 @@ function lazyInit() { async function patchHistoryBack(tab) { ownTabId = tab.id; // use browser history back when 'back to manage' is clicked - if (sessionStorageHash('manageStylesHistory').value[ownTabId] === location.href) { + if (sessionStore['manageStylesHistory' + ownTabId] === location.href) { await onDOMready(); $('#cancel-button').onclick = event => { event.stopPropagation(); @@ -346,8 +346,8 @@ function lazyInit() { } /** resize on 'undo close' */ function restoreWindowSize() { - const pos = tryJSONparse(sessionStorage.windowPos); - delete sessionStorage.windowPos; + const pos = tryJSONparse(sessionStore.windowPos); + delete sessionStore.windowPos; if (pos && pos.left != null && chrome.windows) { chrome.windows.update(chrome.windows.WINDOW_ID_CURRENT, pos); } @@ -408,7 +408,7 @@ function onRuntimeMessage(request) { } function beforeUnload(e) { - sessionStorage.windowPos = JSON.stringify(canSaveWindowPos() && prefs.get('windowPosition')); + sessionStore.windowPos = JSON.stringify(canSaveWindowPos() && prefs.get('windowPosition')); const activeElement = document.activeElement; if (activeElement) { // blurring triggers 'change' or 'input' event if needed diff --git a/edit/sections-editor.js b/edit/sections-editor.js index a2c07773..9fbc8bc5 100644 --- a/edit/sections-editor.js +++ b/edit/sections-editor.js @@ -15,6 +15,7 @@ messageBox prefs sectionsToMozFormat + sessionStore showCodeMirrorPopup showHelp t @@ -117,7 +118,7 @@ function SectionsEditor() { } newStyle = await API.editSave(newStyle); destroyRemovedSections(); - sessionStorage.justEditedStyleId = newStyle.id; + sessionStore.justEditedStyleId = newStyle.id; editor.replaceStyle(newStyle, false); }, diff --git a/edit/source-editor.js b/edit/source-editor.js index ca8cd183..972138a3 100644 --- a/edit/source-editor.js +++ b/edit/source-editor.js @@ -16,6 +16,7 @@ MozSectionWidget prefs sectionsToMozFormat + sessionStore t */ @@ -217,7 +218,7 @@ function SourceEditor() { if (style.id !== newStyle.id) { history.replaceState({}, '', `?id=${newStyle.id}`); } - sessionStorage.justEditedStyleId = newStyle.id; + sessionStore.justEditedStyleId = newStyle.id; Object.assign(style, newStyle); $('#preview-label').classList.remove('hidden'); updateMeta(); diff --git a/js/localization.js b/js/localization.js index e4a8de10..92d448aa 100644 --- a/js/localization.js +++ b/js/localization.js @@ -7,14 +7,8 @@ tDocLoader(); function t(key, params) { - const cache = !params && t.cache[key]; - const s = cache || chrome.i18n.getMessage(key, params); - if (s === '') { - throw `Missing string "${key}"`; - } - if (!params && !cache) { - t.cache[key] = s; - } + const s = chrome.i18n.getMessage(key, params); + if (!s) throw `Missing string "${key}"`; return s; } @@ -138,11 +132,6 @@ function tNodeList(nodes) { function tDocLoader() { t.DOMParser = new DOMParser(); - t.cache = (() => { - try { - return JSON.parse(localStorage.L10N); - } catch (e) {} - })() || {}; t.RX_WORD_BREAK = new RegExp([ '(', /[\d\w\u007B-\uFFFF]{10}/, @@ -154,14 +143,6 @@ function tDocLoader() { /(?!\b|\s|$)/, ].map(rx => rx.source || rx).join(''), 'g'); - // reset L10N cache on UI language change - const UIlang = chrome.i18n.getUILanguage(); - if (t.cache.browserUIlanguage !== UIlang) { - t.cache = {browserUIlanguage: UIlang}; - localStorage.L10N = JSON.stringify(t.cache); - } - const cacheLength = Object.keys(t.cache).length; - Object.assign(tDocLoader, { observer: new MutationObserver(process), start() { @@ -197,9 +178,6 @@ function tDocLoader() { document.removeEventListener('DOMContentLoaded', onLoad); process(tDocLoader.observer.takeRecords()); tDocLoader.stop(); - if (cacheLength !== Object.keys(t.cache).length) { - localStorage.L10N = JSON.stringify(t.cache); - } } } diff --git a/js/messaging.js b/js/messaging.js index ba7ae2ed..9067ee87 100644 --- a/js/messaging.js +++ b/js/messaging.js @@ -1,6 +1,20 @@ -/* exported getTab getActiveTab onTabReady stringAsRegExp openURL ignoreChromeError - getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual - closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */ +/* exported + capitalize + CHROME_HAS_BORDER_BUG + closeCurrentTab + deepEqual + download + getActiveTab + getStyleWithNoCode + getTab + ignoreChromeError + onTabReady + openURL + sessionStore + stringAsRegExp + tryCatch + tryRegExp +*/ 'use strict'; const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(\d+)|$/)[1]); @@ -316,24 +330,28 @@ function deepEqual(a, b, ignoredKeys) { return true; } - -function sessionStorageHash(name) { - return { - name, - value: tryCatch(JSON.parse, sessionStorage[name]) || {}, - set(k, v) { - this.value[k] = v; - this.updateStorage(); - }, - unset(k) { - delete this.value[k]; - this.updateStorage(); - }, - updateStorage() { - sessionStorage[this.name] = JSON.stringify(this.value); +/* A simple polyfill in case DOM storage is disabled in the browser */ +const sessionStore = new Proxy({}, { + get(target, name) { + try { + return sessionStorage[name]; + } catch (e) { + Object.defineProperty(window, 'sessionStorage', {value: target}); } - }; -} + }, + set(target, name, value, proxy) { + try { + sessionStorage[name] = `${value}`; + } catch (e) { + proxy[name]; // eslint-disable-line no-unused-expressions + target[name] = `${value}`; + } + return true; + }, + deleteProperty(target, name) { + return delete target[name]; + }, +}); /** * @param {String} url diff --git a/js/polyfill.js b/js/polyfill.js index 32b19b05..18c0765f 100644 --- a/js/polyfill.js +++ b/js/polyfill.js @@ -66,15 +66,6 @@ self.INJECTED !== 1 && (() => { //#region for our extension pages - for (const storage of ['localStorage', 'sessionStorage']) { - try { - window[storage]._access_check = 1; - delete window[storage]._access_check; - } catch (err) { - Object.defineProperty(window, storage, {value: {}}); - } - } - if (!(new URLSearchParams({foo: 1})).get('foo')) { // TODO: remove when minimum_chrome_version >= 61 window.URLSearchParams = class extends URLSearchParams { diff --git a/manage/manage.js b/manage/manage.js index 721c61cc..23b949f7 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -6,7 +6,7 @@ global messageBox getStyleWithNoCode configDialog sorter msg prefs API $ $$ $create template setupLivePrefs t tWordBreak formatDate - getOwnTab getActiveTab openURL animateElement sessionStorageHash debounce + getOwnTab getActiveTab openURL animateElement sessionStore debounce scrollElementIntoView CHROME VIVALDI router */ 'use strict'; @@ -129,7 +129,7 @@ function showStyles(styles = [], matchUrlIds) { let firstRun = true; installed.dataset.total = styles.length; const scrollY = (history.state || {}).scrollY; - const shouldRenderAll = scrollY > window.innerHeight || sessionStorage.justEditedStyleId; + const shouldRenderAll = scrollY > window.innerHeight || sessionStore.justEditedStyleId; const renderBin = document.createDocumentFragment(); if (scrollY) { renderStyles(); @@ -155,7 +155,7 @@ function showStyles(styles = [], matchUrlIds) { return; } setTimeout(getFaviconImgSrc); - if (sessionStorage.justEditedStyleId) { + if (sessionStore.justEditedStyleId) { highlightEditedStyle(); } else if ('scrollY' in (history.state || {})) { setTimeout(window.scrollTo, 0, 0, history.state.scrollY); @@ -400,7 +400,7 @@ Object.assign(handleEvent, { } else { onVisibilityChange(); getActiveTab().then(tab => { - sessionStorageHash('manageStylesHistory').set(tab.id, url); + sessionStore['manageStylesHistory' + tab.id] = url; location.href = url; }); } @@ -691,10 +691,10 @@ function onVisibilityChange() { // the catch here is that DOM may be outdated so we'll at least refresh the just edited style // assuming other changes aren't important enough to justify making a complicated DOM sync case 'visible': { - const id = sessionStorage.justEditedStyleId; + const id = sessionStore.justEditedStyleId; if (id) { handleUpdateForId(Number(id), {method: 'styleUpdated'}); - delete sessionStorage.justEditedStyleId; + delete sessionStore.justEditedStyleId; } break; } @@ -707,9 +707,9 @@ function onVisibilityChange() { function highlightEditedStyle() { - if (!sessionStorage.justEditedStyleId) return; - const entry = $(ENTRY_ID_PREFIX + sessionStorage.justEditedStyleId); - delete sessionStorage.justEditedStyleId; + if (!sessionStore.justEditedStyleId) return; + const entry = $(ENTRY_ID_PREFIX + sessionStore.justEditedStyleId); + delete sessionStore.justEditedStyleId; if (entry) { animateElement(entry); requestAnimationFrame(() => scrollElementIntoView(entry));