diff options
| author | Alex Yatskov <FooSoft@users.noreply.github.com> | 2019-05-05 18:26:02 -0700 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-05-05 18:26:02 -0700 | 
| commit | 61d1168d94a7467be6e98afc375d7583c0f23cb5 (patch) | |
| tree | 383b42f3b616c033d24f62b8d883121f6687558f /ext/bg/js | |
| parent | 43c5ef87c03307e8281366725f1196307effa9c7 (diff) | |
| parent | f2a5d5095931a78dc388d4cba66953560a336e7f (diff) | |
Merge pull request #160 from toasted-nutbread/mobile
Add support for mobile Firefox
Diffstat (limited to 'ext/bg/js')
| -rw-r--r-- | ext/bg/js/backend.js | 26 | ||||
| -rw-r--r-- | ext/bg/js/database.js | 68 | ||||
| -rw-r--r-- | ext/bg/js/settings.js | 197 | ||||
| -rw-r--r-- | ext/bg/js/util.js | 4 | 
4 files changed, 230 insertions, 65 deletions
| diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 01340419..c191a150 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -28,7 +28,9 @@ class Backend {          await this.translator.prepare();          await apiOptionsSet(await optionsLoad()); -        chrome.commands.onCommand.addListener(this.onCommand.bind(this)); +        if (chrome.commands !== null && typeof chrome.commands === 'object') { +            chrome.commands.onCommand.addListener(this.onCommand.bind(this)); +        }          chrome.runtime.onMessage.addListener(this.onMessage.bind(this));          if (this.options.general.showGuide) { @@ -40,13 +42,13 @@ class Backend {          this.options = utilIsolate(options);          if (!options.general.enable) { -            chrome.browserAction.setBadgeBackgroundColor({color: '#555555'}); -            chrome.browserAction.setBadgeText({text: 'off'}); +            this.setExtensionBadgeBackgroundColor('#555555'); +            this.setExtensionBadgeText('off');          } else if (!dictConfigured(options)) { -            chrome.browserAction.setBadgeBackgroundColor({color: '#f0ad4e'}); -            chrome.browserAction.setBadgeText({text: '!'}); +            this.setExtensionBadgeBackgroundColor('#f0ad4e'); +            this.setExtensionBadgeText('!');          } else { -            chrome.browserAction.setBadgeText({text: ''}); +            this.setExtensionBadgeText('');          }          if (options.anki.enable) { @@ -125,6 +127,18 @@ class Backend {          return true;      } + +    setExtensionBadgeBackgroundColor(color) { +        if (typeof chrome.browserAction.setBadgeBackgroundColor === 'function') { +            chrome.browserAction.setBadgeBackgroundColor({color}); +        } +    } +     +    setExtensionBadgeText(text) { +        if (typeof chrome.browserAction.setBadgeText === 'function') { +            chrome.browserAction.setBadgeText({text}); +        } +    }  }  window.yomichan_backend = new Backend(); diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js index 3c7f6aab..093ec102 100644 --- a/ext/bg/js/database.js +++ b/ext/bg/js/database.js @@ -228,11 +228,47 @@ class Database {          }      } -    async importDictionary(archive, callback) { +    async importDictionary(archive, progressCallback, exceptions) {          if (!this.db) {              throw 'Database not initialized';          } +        const maxTransactionLength = 1000; +        const bulkAdd = async (table, items, total, current) => { +            if (items.length < maxTransactionLength) { +                if (progressCallback) { +                    progressCallback(total, current); +                } + +                try { +                    await table.bulkAdd(items); +                } catch (e) { +                    if (exceptions) { +                        exceptions.push(e); +                    } else { +                        throw e; +                    } +                } +            } else { +                for (let i = 0; i < items.length; i += maxTransactionLength) { +                    if (progressCallback) { +                        progressCallback(total, current + i / items.length); +                    } + +                    let count = Math.min(maxTransactionLength, items.length - i); +                    try { +                        await table.bulkAdd(items.slice(i, i + count)); +                    } catch (e) { +                        if (exceptions) { +                            exceptions.push(e); +                        } else { +                            throw e; +                        } +                    } +                } +            } +        }; +          const indexDataLoaded = async summary => {              if (summary.version > 3) {                  throw 'Unsupported dictionary version'; @@ -247,10 +283,6 @@ class Database {          };          const termDataLoaded = async (summary, entries, total, current) => { -            if (callback) { -                callback(total, current); -            } -              const rows = [];              if (summary.version === 1) {                  for (const [expression, reading, definitionTags, rules, score, ...glossary] of entries) { @@ -280,14 +312,10 @@ class Database {                  }              } -            await this.db.terms.bulkAdd(rows); +            await bulkAdd(this.db.terms, rows, total, current);          };          const termMetaDataLoaded = async (summary, entries, total, current) => { -            if (callback) { -                callback(total, current); -            } -              const rows = [];              for (const [expression, mode, data] of entries) {                  rows.push({ @@ -298,14 +326,10 @@ class Database {                  });              } -            await this.db.termMeta.bulkAdd(rows); +            await bulkAdd(this.db.termMeta, rows, total, current);          };          const kanjiDataLoaded = async (summary, entries, total, current)  => { -            if (callback) { -                callback(total, current); -            } -              const rows = [];              if (summary.version === 1) {                  for (const [character, onyomi, kunyomi, tags, ...meanings] of entries) { @@ -332,14 +356,10 @@ class Database {                  }              } -            await this.db.kanji.bulkAdd(rows); +            await bulkAdd(this.db.kanji, rows, total, current);          };          const kanjiMetaDataLoaded = async (summary, entries, total, current) => { -            if (callback) { -                callback(total, current); -            } -              const rows = [];              for (const [character, mode, data] of entries) {                  rows.push({ @@ -350,14 +370,10 @@ class Database {                  });              } -            await this.db.kanjiMeta.bulkAdd(rows); +            await bulkAdd(this.db.kanjiMeta, rows, total, current);          };          const tagDataLoaded = async (summary, entries, total, current) => { -            if (callback) { -                callback(total, current); -            } -              const rows = [];              for (const [name, category, order, notes, score] of entries) {                  const row = dictTagSanitize({ @@ -372,7 +388,7 @@ class Database {                  rows.push(row);              } -            await this.db.tagMeta.bulkAdd(rows); +            await bulkAdd(this.db.tagMeta, rows, total, current);          };          return await Database.importDictionaryZip( diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 4bf7181f..49bf264d 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -193,7 +193,7 @@ async function onReady() {          await dictionaryGroupsPopulate(options);          await formMainDictionaryOptionsPopulate(options);      } catch (e) { -        dictionaryErrorShow(e); +        dictionaryErrorsShow([e]);      }      try { @@ -203,6 +203,8 @@ async function onReady() {      }      formUpdateVisibility(options); + +    storageInfoInitialize();  }  $(document).ready(utilAsync(onReady)); @@ -212,36 +214,63 @@ $(document).ready(utilAsync(onReady));   * Dictionary   */ -function dictionaryErrorShow(error) { +function dictionaryErrorToString(error) { +    if (error.toString) { +        error = error.toString(); +    } else { +        error = `${error}`; +    } + +    for (const [match, subst] of dictionaryErrorToString.overrides) { +        if (error.includes(match)) { +            error = subst; +            break; +        } +    } + +    return error; +} +dictionaryErrorToString.overrides = [ +    [ +        'A mutation operation was attempted on a database that did not allow mutations.', +        'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.' +    ], +    [ +        'The operation failed for reasons unrelated to the database itself and not covered by any other error code.', +        'Unable to access IndexedDB due to a possibly corrupt user profile. Try using the "Refresh Firefox" feature to reset your user profile.' +    ], +    [ +        'BulkError', +        'Unable to finish importing dictionary data into IndexedDB. This may indicate that you do not have sufficient disk space available to complete this operation.' +    ] +]; + +function dictionaryErrorsShow(errors) {      const dialog = $('#dict-error'); -    if (error) { -        const overrides = [ -            [ -                'A mutation operation was attempted on a database that did not allow mutations.', -                'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.' -            ], -            [ -                'The operation failed for reasons unrelated to the database itself and not covered by any other error code.', -                'Unable to access IndexedDB due to a possibly corrupt user profile. Try using the "Refresh Firefox" feature to reset your user profile.' -            ], -            [ -                'BulkError', -                'Unable to finish importing dictionary data into IndexedDB. This may indicate that you do not have sufficient disk space available to complete this operation.' -            ] -        ]; - -        if (error.toString) { -            error = error.toString(); +    dialog.show().text(''); + +    if (errors !== null && errors.length > 0) { +        const uniqueErrors = {}; +        for (let e of errors) { +            e = dictionaryErrorToString(e); +            uniqueErrors[e] = uniqueErrors.hasOwnProperty(e) ? uniqueErrors[e] + 1 : 1;          } -        for (const [match, subst] of overrides) { -            if (error.includes(match)) { -                error = subst; -                break; +        for (const e in uniqueErrors) { +            const count = uniqueErrors[e]; +            const div = document.createElement('p'); +            if (count > 1) { +                div.textContent = `${e} `; +                const em = document.createElement('em'); +                em.textContent = `(${count})`; +                div.appendChild(em); +            } else { +                div.textContent = `${e}`;              } +            dialog.append($(div));          } -        dialog.show().text(error); +        dialog.show();      } else {          dialog.hide();      } @@ -317,7 +346,7 @@ async function onDictionaryPurge(e) {      const dictProgress = $('#dict-purge').show();      try { -        dictionaryErrorShow(); +        dictionaryErrorsShow(null);          dictionarySpinnerShow(true);          await utilDatabasePurge(); @@ -329,12 +358,16 @@ async function onDictionaryPurge(e) {          await dictionaryGroupsPopulate(options);          await formMainDictionaryOptionsPopulate(options);      } catch (e) { -        dictionaryErrorShow(e); +        dictionaryErrorsShow([e]);      } finally {          dictionarySpinnerShow(false);          dictControls.show();          dictProgress.hide(); + +        if (storageEstimate.mostRecent !== null) { +            storageUpdateStats(); +        }      }  } @@ -344,25 +377,37 @@ async function onDictionaryImport(e) {      const dictProgress = $('#dict-import-progress').show();      try { -        dictionaryErrorShow(); +        dictionaryErrorsShow(null);          dictionarySpinnerShow(true);          const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`); -        const updateProgress = (total, current) => setProgress(current / total * 100.0); +        const updateProgress = (total, current) => { +            setProgress(current / total * 100.0); +            if (storageEstimate.mostRecent !== null && !storageUpdateStats.isUpdating) { +                storageUpdateStats(); +            } +        };          setProgress(0.0); +        const exceptions = [];          const options = await optionsLoad(); -        const summary = await utilDatabaseImport(e.target.files[0], updateProgress); +        const summary = await utilDatabaseImport(e.target.files[0], updateProgress, exceptions);          options.dictionaries[summary.title] = {enabled: true, priority: 0, allowSecondarySearches: false};          if (summary.sequenced && options.general.mainDictionary === '') {              options.general.mainDictionary = summary.title;          } + +        if (exceptions.length > 0) { +            exceptions.push(`Dictionary may not have been imported properly: ${exceptions.length} error${exceptions.length === 1 ? '' : 's'} reported.`); +            dictionaryErrorsShow(exceptions); +        } +          await optionsSave(options);          await dictionaryGroupsPopulate(options);          await formMainDictionaryOptionsPopulate(options);      } catch (e) { -        dictionaryErrorShow(e); +        dictionaryErrorsShow([e]);      } finally {          dictionarySpinnerShow(false); @@ -520,3 +565,93 @@ async function onAnkiFieldTemplatesReset(e) {          ankiErrorShow(e);      }  } + + +/* + * Storage + */ + +async function getBrowser() { +    if (typeof chrome !== "undefined") { +        if (typeof browser !== "undefined") { +            try { +                const info = await browser.runtime.getBrowserInfo(); +                if (info.name === "Fennec") { +                    return "firefox-mobile"; +                } +            } catch (e) { } +            return "firefox"; +        } else { +            return "chrome"; +        } +    } else { +        return "edge"; +    } +} + +function storageBytesToLabeledString(size) { +    const base = 1000; +    const labels = ["bytes", "KB", "MB", "GB"]; +    let labelIndex = 0; +    while (size >= base) { +        size /= base; +        ++labelIndex; +    } +    const label = size.toFixed(1); +    return `${label}${labels[labelIndex]}`; +} + +async function storageEstimate() { +    try { +        return (storageEstimate.mostRecent = await navigator.storage.estimate()); +    } catch (e) { } +    return null; +} +storageEstimate.mostRecent = null; + +async function storageInfoInitialize() { +    const browser = await getBrowser(); +    const container = document.querySelector("#storage-info"); +    container.setAttribute("data-browser", browser); + +    await storageShowInfo(); + +    container.classList.remove("storage-hidden"); + +    document.querySelector("#storage-refresh").addEventListener('click', () => storageShowInfo(), false); +} + +async function storageUpdateStats() { +    storageUpdateStats.isUpdating = true; + +    const estimate = await storageEstimate(); +    const valid = (estimate !== null); + +    if (valid) { +        document.querySelector("#storage-usage").textContent = storageBytesToLabeledString(estimate.usage); +        document.querySelector("#storage-quota").textContent = storageBytesToLabeledString(estimate.quota); +    } + +    storageUpdateStats.isUpdating = false; +    return valid; +} +storageUpdateStats.isUpdating = false; + +async function storageShowInfo() { +    storageSpinnerShow(true); + +    const valid = await storageUpdateStats(); +    document.querySelector("#storage-use").classList.toggle("storage-hidden", !valid); +    document.querySelector("#storage-error").classList.toggle("storage-hidden", valid); + +    storageSpinnerShow(false); +} + +function storageSpinnerShow(show) { +    const spinner = $('#storage-spinner'); +    if (show) { +        spinner.show(); +    } else { +        spinner.hide(); +    } +} diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 216cef3f..34b06ddb 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -87,6 +87,6 @@ function utilDatabasePurge() {      return utilBackend().translator.database.purge();  } -function utilDatabaseImport(data, progress) { -    return utilBackend().translator.database.importDictionary(data, progress); +function utilDatabaseImport(data, progress, exceptions) { +    return utilBackend().translator.database.importDictionary(data, progress, exceptions);  } |