diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/background.html | 29 | ||||
| -rw-r--r-- | ext/bg/js/anki-connect.js (renamed from ext/bg/js/ankiconnect.js) | 1 | ||||
| -rw-r--r-- | ext/bg/js/anki-null.js (renamed from ext/bg/js/ankinull.js) | 1 | ||||
| -rw-r--r-- | ext/bg/js/database.js | 14 | ||||
| -rw-r--r-- | ext/bg/js/gecko.js | 1 | ||||
| -rw-r--r-- | ext/bg/js/options-form.js | 366 | ||||
| -rw-r--r-- | ext/bg/js/options.js | 451 | ||||
| -rw-r--r-- | ext/bg/js/popup.js | 3 | ||||
| -rw-r--r-- | ext/bg/js/translator.js | 24 | ||||
| -rw-r--r-- | ext/bg/js/util.js | 268 | ||||
| -rw-r--r-- | ext/bg/js/yomichan.js | 8 | ||||
| -rw-r--r-- | ext/bg/options.html | 1 | 
12 files changed, 591 insertions, 576 deletions
| diff --git a/ext/bg/background.html b/ext/bg/background.html index 625917ef..eecadf1e 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -1,18 +1,17 @@  <!DOCTYPE html>  <html lang="en"> -<body> -    <script src="../lib/handlebars.min.js"></script> -    <script src="../lib/dexie.min.js"></script> -    <script src="../lib/wanakana.min.js"></script> -    <script src="js/gecko.js"></script> -    <script src="js/ankiconnect.js"></script> -    <script src="js/ankinull.js"></script> -    <script src="js/templates.js"></script> -    <script src="js/util.js"></script> -    <script src="js/database.js"></script> -    <script src="js/deinflector.js"></script> -    <script src="js/translator.js"></script> -    <script src="js/options.js"></script> -    <script src="js/yomichan.js"></script> -</body> +    <body> +        <script src="../lib/handlebars.min.js"></script> +        <script src="../lib/dexie.min.js"></script> +        <script src="../lib/wanakana.min.js"></script> +        <script src="js/templates.js"></script> +        <script src="js/gecko.js"></script> +        <script src="js/util.js"></script> +        <script src="js/anki-connect.js"></script> +        <script src="js/anki-null.js"></script> +        <script src="js/database.js"></script> +        <script src="js/deinflector.js"></script> +        <script src="js/translator.js"></script> +        <script src="js/yomichan.js"></script> +    </body>  </html> diff --git a/ext/bg/js/ankiconnect.js b/ext/bg/js/anki-connect.js index 3a6e3690..9759c8f5 100644 --- a/ext/bg/js/ankiconnect.js +++ b/ext/bg/js/anki-connect.js @@ -16,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +  class AnkiConnect {      constructor(server) {          this.server = server; diff --git a/ext/bg/js/ankinull.js b/ext/bg/js/anki-null.js index 0d0ed903..99dc2f30 100644 --- a/ext/bg/js/ankinull.js +++ b/ext/bg/js/anki-null.js @@ -16,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +  class AnkiNull {      addNote(note) {          return Promise.reject('unsupported action'); diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js index 31573065..51f639d9 100644 --- a/ext/bg/js/database.js +++ b/ext/bg/js/database.js @@ -76,8 +76,8 @@ class Database {                  results.push({                      expression: row.expression,                      reading: row.reading, -                    tags: splitField(row.tags), -                    rules: splitField(row.rules), +                    tags: dictFieldSplit(row.tags), +                    rules: dictFieldSplit(row.rules),                      glossary: row.glossary,                      score: row.score,                      dictionary: row.dictionary, @@ -105,9 +105,9 @@ class Database {              if (dictionaries.includes(row.dictionary)) {                  results.push({                      character: row.character, -                    onyomi: splitField(row.onyomi), -                    kunyomi: splitField(row.kunyomi), -                    tags: splitField(row.tags), +                    onyomi: dictFieldSplit(row.onyomi), +                    kunyomi: dictFieldSplit(row.kunyomi), +                    tags: dictFieldSplit(row.tags),                      glossary: row.meanings,                      dictionary: row.dictionary                  }); @@ -172,7 +172,7 @@ class Database {                      const rows = [];                      for (const tag in tagMeta || {}) {                          const meta = tagMeta[tag]; -                        const row = sanitizeTag({ +                        const row = dictTagSanitize({                              name: tag,                              category: meta.category,                              notes: meta.notes, @@ -229,6 +229,6 @@ class Database {              });          }; -        return importJsonDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded).then(() => summary); +        return jsonLoadDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded).then(() => summary);      }  } diff --git a/ext/bg/js/gecko.js b/ext/bg/js/gecko.js index f195fffc..3df07f0b 100644 --- a/ext/bg/js/gecko.js +++ b/ext/bg/js/gecko.js @@ -20,6 +20,7 @@   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   */ +  if (!chrome.storage.sync) {      // https://bugzilla.mozilla.org/show_bug.cgi?id=1220494      chrome.storage.sync = chrome.storage.local; diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js deleted file mode 100644 index c53c0c5e..00000000 --- a/ext/bg/js/options-form.js +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2016  Alex Yatskov <alex@foosoft.net> - * Author: Alex Yatskov <alex@foosoft.net> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -// -//  General -// - -function getFormData() { -    return optionsLoad().then(optionsOld => { -        const optionsNew = $.extend(true, {}, optionsOld); - -        optionsNew.general.audioPlayback = $('#audio-playback-buttons').prop('checked'); -        optionsNew.general.groupResults = $('#group-terms-results').prop('checked'); -        optionsNew.general.softKatakana = $('#soft-katakana-search').prop('checked'); -        optionsNew.general.showAdvanced = $('#show-advanced-options').prop('checked'); -        optionsNew.general.maxResults = parseInt($('#max-displayed-results').val(), 10); - -        optionsNew.scanning.requireShift = $('#hold-shift-to-scan').prop('checked'); -        optionsNew.scanning.selectText = $('#select-matched-text').prop('checked'); -        optionsNew.scanning.imposter = $('#search-form-text-fields').prop('checked'); -        optionsNew.scanning.delay = parseInt($('#scan-delay').val(), 10); -        optionsNew.scanning.length = parseInt($('#scan-length').val(), 10); - -        optionsNew.anki.enable = $('#anki-enable').prop('checked'); -        optionsNew.anki.tags = $('#card-tags').val().split(/[,; ]+/); -        optionsNew.anki.htmlCards = $('#generate-html-cards').prop('checked'); -        optionsNew.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10); -        optionsNew.anki.server = $('#interface-server').val(); -        if (optionsOld.anki.enable) { -            optionsNew.anki.terms.deck = $('#anki-terms-deck').val(); -            optionsNew.anki.terms.model = $('#anki-terms-model').val(); -            optionsNew.anki.terms.fields = ankiFieldsToDict($('#terms .anki-field-value')); -            optionsNew.anki.kanji.deck = $('#anki-kanji-deck').val(); -            optionsNew.anki.kanji.model = $('#anki-kanji-model').val(); -            optionsNew.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value')); -        } - -        $('.dict-group').each((index, element) => { -            const dictionary = $(element); -            const title = dictionary.data('title'); -            const priority = parseInt(dictionary.find('.dict-priority').val(), 10); -            const enabled = dictionary.find('.dict-enabled').prop('checked'); -            optionsNew.dictionaries[title] = {priority, enabled}; -        }); - -        return {optionsNew, optionsOld}; -    }); -} - -function updateVisibility(options) { -    const general = $('#anki-general'); -    if (options.anki.enable) { -        general.show(); -    } else { -        general.hide(); -    } - -    const advanced = $('.options-advanced'); -    if (options.general.showAdvanced) { -        advanced.show(); -    } else { -        advanced.hide(); -    } -} - -$(document).ready(() => { -    Handlebars.partials = Handlebars.templates; - -    optionsLoad().then(options => { -        $('#audio-playback-buttons').prop('checked', options.general.audioPlayback); -        $('#group-terms-results').prop('checked', options.general.groupResults); -        $('#soft-katakana-search').prop('checked', options.general.softKatakana); -        $('#show-advanced-options').prop('checked', options.general.showAdvanced); -        $('#max-displayed-results').val(options.general.maxResults); - -        $('#hold-shift-to-scan').prop('checked', options.scanning.requireShift); -        $('#select-matched-text').prop('checked', options.scanning.selectText); -        $('#search-form-text-fields').prop('checked', options.scanning.imposter); -        $('#scan-delay').val(options.scanning.delay); -        $('#scan-length').val(options.scanning.length); - -        $('#dict-purge').click(onDictionaryPurge); -        $('#dict-importer a').click(onDictionarySetUrl); -        $('#dict-import').click(onDictionaryImport); -        $('#dict-url').on('input', onDictionaryUpdateUrl); - -        $('#anki-enable').prop('checked', options.anki.enable); -        $('#card-tags').val(options.anki.tags.join(' ')); -        $('#generate-html-cards').prop('checked', options.anki.htmlCards); -        $('#sentence-detection-extent').val(options.anki.sentenceExt); -        $('#interface-server').val(options.anki.server); -        $('input, select').not('.anki-model').change(onOptionsChanged); -        $('.anki-model').change(onAnkiModelChanged); - -        populateDictionaries(options); -        populateAnkiDeckAndModel(options); -        updateVisibility(options); -    }); -}); - -// -//  Dictionary -// - -function showDictionaryError(error) { -    const dialog = $('#dict-error'); -    if (error) { -        dialog.show().find('span').text(error); -    } else { -        dialog.hide(); -    } -} - -function showDictionarySpinner(show) { -    const spinner = $('#dict-spinner'); -    if (show) { -        spinner.show(); -    } else { -        spinner.hide(); -    } -} - -function populateDictionaries(options) { -    showDictionaryError(null); -    showDictionarySpinner(true); - -    const dictGroups = $('#dict-groups').empty(); -    const dictWarning = $('#dict-warning').hide(); - -    let dictCount = 0; -    return getDatabase().getDictionaries().then(rows => { -        rows.forEach(row => { -            const dictOptions = options.dictionaries[row.title] || {enableTerms: false, enableKanji: false, priority: 0}; -            const html = Handlebars.templates['dictionary.html']({ -                title: row.title, -                version: row.version, -                revision: row.revision, -                priority: dictOptions.priority, -                enabled: dictOptions.enabled -            }); - -            dictGroups.append($(html)); -            ++dictCount; -        }); - -        updateVisibility(options); - -        $('.dict-enabled, .dict-priority').change(onOptionsChanged); -    }).catch(showDictionaryError).then(() => { -        showDictionarySpinner(false); -        if (dictCount === 0) { -            dictWarning.show(); -        } -    }); -} - -function onDictionaryPurge(e) { -    e.preventDefault(); - -    showDictionaryError(null); -    showDictionarySpinner(true); - -    const dictControls = $('#dict-importer, #dict-groups').hide(); -    const dictProgress = $('#dict-purge-progress').show(); - -    return getDatabase().purge().catch(showDictionaryError).then(() => { -        showDictionarySpinner(false); -        dictControls.show(); -        dictProgress.hide(); -        return optionsLoad(); -    }).then(options => { -        options.dictionaries = {}; -        return optionsSave(options).then(() => { -            populateDictionaries(options); -            getYomichan().setOptions(options); -        }); -    }); -} - -function onDictionaryImport() { -    showDictionaryError(null); -    showDictionarySpinner(true); - -    const dictUrl = $('#dict-url'); -    const dictImporter = $('#dict-importer').hide(); -    const dictProgress = $('#dict-import-progress').show(); -    const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`); - -    setProgress(0.0); - -    optionsLoad().then(options => { -        getDatabase().importDictionary(dictUrl.val(), (total, current) => setProgress(current / total * 100.0)).then(summary => { -            options.dictionaries[summary.title] = {enabled: true, priority: 0}; -            return optionsSave(options).then(() => getYomichan().setOptions(options)); -        }).then(() => populateDictionaries(options)).catch(showDictionaryError).then(() => { -            showDictionarySpinner(false); -            dictProgress.hide(); -            dictImporter.show(); -            dictUrl.val(''); -            dictUrl.trigger('input'); -        }); -    }); -} - -function onDictionarySetUrl(e) { -    e.preventDefault(); - -    const dictUrl = $('#dict-url'); -    const url = $(this).data('url'); -    if (url.includes('/')) { -        dictUrl.val(url); -    } else { -        dictUrl.val(chrome.extension.getURL(`bg/lang/data/${url}/index.json`)); -    } - -    dictUrl.trigger('input'); -} - -function onDictionaryUpdateUrl() { -    $('#dict-import').prop('disabled', $(this).val().length === 0); -} - -// -//  Anki -// - -function showAnkiSpinner(show) { -    const spinner = $('#anki-spinner'); -    if (show) { -        spinner.show(); -    } else { -        spinner.hide(); -    } -} - -function showAnkiError(error) { -    const dialog = $('#anki-error'); -    if (error) { -        dialog.show().find('span').text(error); -    } -    else { -        dialog.hide(); -    } -} - -function ankiFieldsToDict(selection) { -    const result = {}; -    selection.each((index, element) => { -        result[$(element).data('field')] = $(element).val(); -    }); - -    return result; -} - -function populateAnkiDeckAndModel(options) { -    showAnkiError(null); -    showAnkiSpinner(true); - -    const ankiFormat = $('#anki-format').hide(); -    return Promise.all([getAnki().getDeckNames(), getAnki().getModelNames()]).then(([deckNames, modelNames]) => { -        const ankiDeck = $('.anki-deck'); -        ankiDeck.find('option').remove(); -        deckNames.sort().forEach(name => ankiDeck.append($('<option/>', {value: name, text: name}))); - -        $('#anki-terms-deck').val(options.anki.terms.deck); -        $('#anki-kanji-deck').val(options.anki.kanji.deck); - -        const ankiModel = $('.anki-model'); -        ankiModel.find('option').remove(); -        modelNames.sort().forEach(name => ankiModel.append($('<option/>', {value: name, text: name}))); - -        return Promise.all([ -            populateAnkiFields($('#anki-terms-model').val(options.anki.terms.model), options), -            populateAnkiFields($('#anki-kanji-model').val(options.anki.kanji.model), options) -        ]); -    }).then(() => ankiFormat.show()).catch(showAnkiError).then(() => showAnkiSpinner(false)); -} - -function populateAnkiFields(element, options) { -    const tab = element.closest('.tab-pane'); -    const tabId = tab.attr('id'); -    const container = tab.find('tbody').empty(); - -    const modelName = element.val(); -    if (modelName === null) { -        return Promise.resolve(); -    } - -    const markers = { -        'terms': ['audio', 'dictionary', 'expression', 'furigana', 'glossary', 'reading', 'sentence', 'tags', 'url'], -        'kanji': ['character', 'dictionary', 'glossary', 'kunyomi', 'onyomi', 'sentence', 'tags', 'url'] -    }[tabId] || {}; - -    return getAnki().getModelFieldNames(modelName).then(names => { -        names.forEach(name => { -            const value = options.anki[tabId].fields[name] || ''; -            const html = Handlebars.templates['model.html']({name, markers, value}); -            container.append($(html)); -        }); - -        tab.find('.anki-field-value').change(onOptionsChanged); -        tab.find('.marker-link').click(e => { -            e.preventDefault(); -            const link = e.target; -            $(link).closest('.input-group').find('.anki-field-value').val(`{${link.text}}`).trigger('change'); -        }); -    }); -} - -function onAnkiModelChanged(e) { -    if (!e.originalEvent) { -        return; -    } - -    showAnkiError(null); -    showAnkiSpinner(true); - -    const element = $(this); -    getFormData().then(({optionsNew, optionsOld}) => { -        const tab = element.closest('.tab-pane'); -        const tabId = tab.attr('id'); - -        optionsNew.anki[tabId].fields = {}; -        populateAnkiFields(element, optionsNew).then(() => { -            optionsSave(optionsNew).then(() => getYomichan().setOptions(optionsNew)); -        }).catch(showAnkiError).then(() => showAnkiSpinner(false)); -    }); -} - -function onOptionsChanged(e) { -    if (!e.originalEvent && !e.isTrigger) { -        return; -    } - -    getFormData().then(({optionsNew, optionsOld}) => { -        return optionsSave(optionsNew).then(() => { -            getYomichan().setOptions(optionsNew); -            updateVisibility(optionsNew); - -            const ankiUpdated = -                optionsNew.anki.enable !== optionsOld.anki.enable || -                optionsNew.anki.server !== optionsOld.anki.server; - -            if (ankiUpdated) { -                showAnkiError(null); -                showAnkiSpinner(true); -                return populateAnkiDeckAndModel(optionsNew); -            } -        }); -    }).catch(showAnkiError).then(() => showAnkiSpinner(false)); -} diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 198deb6d..565ccd41 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -17,143 +17,352 @@   */ -function optionsSetDefaults(options) { -    const defaults = { -        general: { -            enable: true, -            audioPlayback: true, -            groupResults: true, -            softKatakana: true, -            maxResults: 32, -            showAdvanced: false -        }, - -        scanning: { -            requireShift: true, -            selectText: true, -            imposter: true, -            delay: 15, -            length: 10 -        }, - -        dictionaries: {}, - -        anki: { -            enable: false, -            server: 'http://127.0.0.1:8765', -            tags: ['yomichan'], -            htmlCards: true, -            sentenceExt: 200, -            terms: {deck: '', model: '', fields: {}}, -            kanji: {deck: '', model: '', fields: {}} -        } -    }; +/* + * General + */ -    const combine = (target, source) => { -        for (const key in source) { -            if (!target.hasOwnProperty(key)) { -                target[key] = source[key]; -            } +function getFormData() { +    return optionsLoad().then(optionsOld => { +        const optionsNew = $.extend(true, {}, optionsOld); + +        optionsNew.general.audioPlayback = $('#audio-playback-buttons').prop('checked'); +        optionsNew.general.groupResults = $('#group-terms-results').prop('checked'); +        optionsNew.general.softKatakana = $('#soft-katakana-search').prop('checked'); +        optionsNew.general.showAdvanced = $('#show-advanced-options').prop('checked'); +        optionsNew.general.maxResults = parseInt($('#max-displayed-results').val(), 10); + +        optionsNew.scanning.requireShift = $('#hold-shift-to-scan').prop('checked'); +        optionsNew.scanning.selectText = $('#select-matched-text').prop('checked'); +        optionsNew.scanning.imposter = $('#search-form-text-fields').prop('checked'); +        optionsNew.scanning.delay = parseInt($('#scan-delay').val(), 10); +        optionsNew.scanning.length = parseInt($('#scan-length').val(), 10); + +        optionsNew.anki.enable = $('#anki-enable').prop('checked'); +        optionsNew.anki.tags = $('#card-tags').val().split(/[,; ]+/); +        optionsNew.anki.htmlCards = $('#generate-html-cards').prop('checked'); +        optionsNew.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10); +        optionsNew.anki.server = $('#interface-server').val(); +        if (optionsOld.anki.enable) { +            optionsNew.anki.terms.deck = $('#anki-terms-deck').val(); +            optionsNew.anki.terms.model = $('#anki-terms-model').val(); +            optionsNew.anki.terms.fields = ankiFieldsToDict($('#terms .anki-field-value')); +            optionsNew.anki.kanji.deck = $('#anki-kanji-deck').val(); +            optionsNew.anki.kanji.model = $('#anki-kanji-model').val(); +            optionsNew.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value'));          } -    }; - -    combine(options, defaults); -    combine(options.general, defaults.general); -    combine(options.scanning, defaults.scanning); -    combine(options.anki, defaults.anki); -    combine(options.anki.terms, defaults.anki.terms); -    combine(options.anki.kanji, defaults.anki.kanji); - -    return options; -} - - -function optionsVersion(options) { -    const fixups = [ -        () => { -            const copy = (targetDict, targetKey, sourceDict, sourceKey) => { -                targetDict[targetKey] = sourceDict.hasOwnProperty(sourceKey) ? sourceDict[sourceKey] : targetDict[targetKey]; -            }; - -            copy(options.general, 'autoStart', options, 'activateOnStartup'); -            copy(options.general, 'audioPlayback', options, 'enableAudioPlayback'); -            copy(options.general, 'softKatakana', options, 'enableSoftKatakanaSearch'); -            copy(options.general, 'groupResults', options, 'groupTermResults'); -            copy(options.general, 'showAdvanced', options, 'showAdvancedOptions'); - -            copy(options.scanning, 'requireShift', options, 'holdShiftToScan'); -            copy(options.scanning, 'selectText', options, 'selectMatchedText'); -            copy(options.scanning, 'delay', options, 'scanDelay'); -            copy(options.scanning, 'length', options, 'scanLength'); - -            options.anki.enable = options.ankiMethod === 'ankiconnect'; - -            copy(options.anki, 'tags', options, 'ankiCardTags'); -            copy(options.anki, 'sentenceExt', options, 'sentenceExtent'); -            copy(options.anki.terms, 'deck', options, 'ankiTermDeck'); -            copy(options.anki.terms, 'model', options, 'ankiTermModel'); -            copy(options.anki.terms, 'fields', options, 'ankiTermFields'); -            copy(options.anki.kanji, 'deck', options, 'ankiKanjiDeck'); -            copy(options.anki.kanji, 'model', options, 'ankiKanjiModel'); -            copy(options.anki.kanji, 'fields', options, 'ankiKanjiFields'); - -            for (const title in options.dictionaries) { -                const dictionary = options.dictionaries[title]; -                dictionary.enabled = dictionary.enableTerms || dictionary.enableKanji; -                dictionary.priority = 0; -            } -        }, -        () => { -            const fixupFields = fields => { -                const fixups = { -                    '{expression-furigana}': '{furigana}', -                    '{glossary-list}': '{glossary}' -                }; - -                for (const name in fields) { -                    for (const fixup in fixups) { -                        fields[name] = fields[name].replace(fixup, fixups[fixup]); -                    } -                } -            }; - -            fixupFields(options.anki.terms.fields); -            fixupFields(options.anki.kanji.fields); + +        $('.dict-group').each((index, element) => { +            const dictionary = $(element); +            const title = dictionary.data('title'); +            const priority = parseInt(dictionary.find('.dict-priority').val(), 10); +            const enabled = dictionary.find('.dict-enabled').prop('checked'); +            optionsNew.dictionaries[title] = {priority, enabled}; +        }); + +        return {optionsNew, optionsOld}; +    }); +} + +function updateVisibility(options) { +    const general = $('#anki-general'); +    if (options.anki.enable) { +        general.show(); +    } else { +        general.hide(); +    } + +    const advanced = $('.options-advanced'); +    if (options.general.showAdvanced) { +        advanced.show(); +    } else { +        advanced.hide(); +    } +} + +$(document).ready(() => { +    Handlebars.partials = Handlebars.templates; + +    optionsLoad().then(options => { +        $('#audio-playback-buttons').prop('checked', options.general.audioPlayback); +        $('#group-terms-results').prop('checked', options.general.groupResults); +        $('#soft-katakana-search').prop('checked', options.general.softKatakana); +        $('#show-advanced-options').prop('checked', options.general.showAdvanced); +        $('#max-displayed-results').val(options.general.maxResults); + +        $('#hold-shift-to-scan').prop('checked', options.scanning.requireShift); +        $('#select-matched-text').prop('checked', options.scanning.selectText); +        $('#search-form-text-fields').prop('checked', options.scanning.imposter); +        $('#scan-delay').val(options.scanning.delay); +        $('#scan-length').val(options.scanning.length); + +        $('#dict-purge').click(onDictionaryPurge); +        $('#dict-importer a').click(onDictionarySetUrl); +        $('#dict-import').click(onDictionaryImport); +        $('#dict-url').on('input', onDictionaryUpdateUrl); + +        $('#anki-enable').prop('checked', options.anki.enable); +        $('#card-tags').val(options.anki.tags.join(' ')); +        $('#generate-html-cards').prop('checked', options.anki.htmlCards); +        $('#sentence-detection-extent').val(options.anki.sentenceExt); +        $('#interface-server').val(options.anki.server); +        $('input, select').not('.anki-model').change(onOptionsChanged); +        $('.anki-model').change(onAnkiModelChanged); + +        populateDictionaries(options); +        populateAnkiDeckAndModel(options); +        updateVisibility(options); +    }); +}); + + +/* + * Dictionary + */ + +function showDictionaryError(error) { +    const dialog = $('#dict-error'); +    if (error) { +        dialog.show().find('span').text(error); +    } else { +        dialog.hide(); +    } +} + +function showDictionarySpinner(show) { +    const spinner = $('#dict-spinner'); +    if (show) { +        spinner.show(); +    } else { +        spinner.hide(); +    } +} + +function populateDictionaries(options) { +    showDictionaryError(null); +    showDictionarySpinner(true); + +    const dictGroups = $('#dict-groups').empty(); +    const dictWarning = $('#dict-warning').hide(); + +    let dictCount = 0; +    return instDb().getDictionaries().then(rows => { +        rows.forEach(row => { +            const dictOptions = options.dictionaries[row.title] || {enableTerms: false, enableKanji: false, priority: 0}; +            const html = Handlebars.templates['dictionary.html']({ +                title: row.title, +                version: row.version, +                revision: row.revision, +                priority: dictOptions.priority, +                enabled: dictOptions.enabled +            }); + +            dictGroups.append($(html)); +            ++dictCount; +        }); + +        updateVisibility(options); + +        $('.dict-enabled, .dict-priority').change(onOptionsChanged); +    }).catch(showDictionaryError).then(() => { +        showDictionarySpinner(false); +        if (dictCount === 0) { +            dictWarning.show();          } -    ]; +    }); +} + +function onDictionaryPurge(e) { +    e.preventDefault(); + +    showDictionaryError(null); +    showDictionarySpinner(true); -    optionsSetDefaults(options); -    if (!options.hasOwnProperty('version')) { -        options.version = fixups.length; +    const dictControls = $('#dict-importer, #dict-groups').hide(); +    const dictProgress = $('#dict-purge-progress').show(); + +    return instDb().purge().catch(showDictionaryError).then(() => { +        showDictionarySpinner(false); +        dictControls.show(); +        dictProgress.hide(); +        return optionsLoad(); +    }).then(options => { +        options.dictionaries = {}; +        return optionsSave(options).then(() => { +            populateDictionaries(options); +            instYomi().setOptions(options); +        }); +    }); +} + +function onDictionaryImport() { +    showDictionaryError(null); +    showDictionarySpinner(true); + +    const dictUrl = $('#dict-url'); +    const dictImporter = $('#dict-importer').hide(); +    const dictProgress = $('#dict-import-progress').show(); +    const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`); + +    setProgress(0.0); + +    optionsLoad().then(options => { +        instDb().importDictionary(dictUrl.val(), (total, current) => setProgress(current / total * 100.0)).then(summary => { +            options.dictionaries[summary.title] = {enabled: true, priority: 0}; +            return optionsSave(options).then(() => instYomi().setOptions(options)); +        }).then(() => populateDictionaries(options)).catch(showDictionaryError).then(() => { +            showDictionarySpinner(false); +            dictProgress.hide(); +            dictImporter.show(); +            dictUrl.val(''); +            dictUrl.trigger('input'); +        }); +    }); +} + +function onDictionarySetUrl(e) { +    e.preventDefault(); + +    const dictUrl = $('#dict-url'); +    const url = $(this).data('url'); +    if (url.includes('/')) { +        dictUrl.val(url); +    } else { +        dictUrl.val(chrome.extension.getURL(`bg/lang/data/${url}/index.json`));      } -    while (options.version < fixups.length) { -        fixups[options.version++](); +    dictUrl.trigger('input'); +} + +function onDictionaryUpdateUrl() { +    $('#dict-import').prop('disabled', $(this).val().length === 0); +} + +/* + * Anki + */ + +function showAnkiSpinner(show) { +    const spinner = $('#anki-spinner'); +    if (show) { +        spinner.show(); +    } else { +        spinner.hide(); +    } +} + +function showAnkiError(error) { +    const dialog = $('#anki-error'); +    if (error) { +        dialog.show().find('span').text(error); +    } +    else { +        dialog.hide();      } +} + +function ankiFieldsToDict(selection) { +    const result = {}; +    selection.each((index, element) => { +        result[$(element).data('field')] = $(element).val(); +    }); -    return options; +    return result;  } -function optionsLoad() { -    return new Promise((resolve, reject) => { -        chrome.storage.sync.get(null, options => resolve(optionsVersion(options))); +function populateAnkiDeckAndModel(options) { +    showAnkiError(null); +    showAnkiSpinner(true); + +    const ankiFormat = $('#anki-format').hide(); +    return Promise.all([instAnki().getDeckNames(), instAnki().getModelNames()]).then(([deckNames, modelNames]) => { +        const ankiDeck = $('.anki-deck'); +        ankiDeck.find('option').remove(); +        deckNames.sort().forEach(name => ankiDeck.append($('<option/>', {value: name, text: name}))); + +        $('#anki-terms-deck').val(options.anki.terms.deck); +        $('#anki-kanji-deck').val(options.anki.kanji.deck); + +        const ankiModel = $('.anki-model'); +        ankiModel.find('option').remove(); +        modelNames.sort().forEach(name => ankiModel.append($('<option/>', {value: name, text: name}))); + +        return Promise.all([ +            populateAnkiFields($('#anki-terms-model').val(options.anki.terms.model), options), +            populateAnkiFields($('#anki-kanji-model').val(options.anki.kanji.model), options) +        ]); +    }).then(() => ankiFormat.show()).catch(showAnkiError).then(() => showAnkiSpinner(false)); +} + +function populateAnkiFields(element, options) { +    const tab = element.closest('.tab-pane'); +    const tabId = tab.attr('id'); +    const container = tab.find('tbody').empty(); + +    const modelName = element.val(); +    if (modelName === null) { +        return Promise.resolve(); +    } + +    const markers = { +        'terms': ['audio', 'dictionary', 'expression', 'furigana', 'glossary', 'reading', 'sentence', 'tags', 'url'], +        'kanji': ['character', 'dictionary', 'glossary', 'kunyomi', 'onyomi', 'sentence', 'tags', 'url'] +    }[tabId] || {}; + +    return instAnki().getModelFieldNames(modelName).then(names => { +        names.forEach(name => { +            const value = options.anki[tabId].fields[name] || ''; +            const html = Handlebars.templates['model.html']({name, markers, value}); +            container.append($(html)); +        }); + +        tab.find('.anki-field-value').change(onOptionsChanged); +        tab.find('.marker-link').click(e => { +            e.preventDefault(); +            const link = e.target; +            $(link).closest('.input-group').find('.anki-field-value').val(`{${link.text}}`).trigger('change'); +        });      });  } -function optionsSave(options) { -    return new Promise((resolve, reject) => { -        chrome.storage.sync.set(options, resolve); +function onAnkiModelChanged(e) { +    if (!e.originalEvent) { +        return; +    } + +    showAnkiError(null); +    showAnkiSpinner(true); + +    const element = $(this); +    getFormData().then(({optionsNew, optionsOld}) => { +        const tab = element.closest('.tab-pane'); +        const tabId = tab.attr('id'); + +        optionsNew.anki[tabId].fields = {}; +        populateAnkiFields(element, optionsNew).then(() => { +            optionsSave(optionsNew).then(() => instYomi().setOptions(optionsNew)); +        }).catch(showAnkiError).then(() => showAnkiSpinner(false));      });  } -function optionsEnabledDicts(options) { -    const dictionaries = {}; -    for (const title in options.dictionaries) { -        const dictionary = options.dictionaries[title]; -        if (dictionary.enabled) { -            dictionaries[title] = dictionary; -        } +function onOptionsChanged(e) { +    if (!e.originalEvent && !e.isTrigger) { +        return;      } -    return dictionaries; +    getFormData().then(({optionsNew, optionsOld}) => { +        return optionsSave(optionsNew).then(() => { +            instYomi().setOptions(optionsNew); +            updateVisibility(optionsNew); + +            const ankiUpdated = +                optionsNew.anki.enable !== optionsOld.anki.enable || +                optionsNew.anki.server !== optionsOld.anki.server; + +            if (ankiUpdated) { +                showAnkiError(null); +                showAnkiSpinner(true); +                return populateAnkiDeckAndModel(optionsNew); +            } +        }); +    }).catch(showAnkiError).then(() => showAnkiSpinner(false));  } diff --git a/ext/bg/js/popup.js b/ext/bg/js/popup.js index 4f6942f0..0d1fb04e 100644 --- a/ext/bg/js/popup.js +++ b/ext/bg/js/popup.js @@ -16,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +  $(document).ready(() => {      $('#open-search').click(() => window.open(chrome.extension.getURL('bg/search.html')));      $('#open-options').click(() => chrome.runtime.openOptionsPage()); @@ -27,7 +28,7 @@ $(document).ready(() => {          toggle.bootstrapToggle();          toggle.change(() => {              options.general.enable = toggle.prop('checked'); -            optionsSave(options).then(() => getYomichan().setOptions(options)); +            optionsSave(options).then(() => instYomi().setOptions(options));          });      });  }); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index e7c2aac2..967b8bfe 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -31,7 +31,7 @@ class Translator {          }          const promises = [ -            loadJsonInt('bg/lang/deinflect.json'), +            jsonLoadInt('bg/lang/deinflect.json'),              this.database.prepare()          ]; @@ -56,8 +56,8 @@ class Translator {              let definitions = [];              for (const deinflection of deinflections) {                  for (const definition of deinflection.definitions) { -                    const tags = definition.tags.map(tag => buildTag(tag, definition.tagMeta)); -                    tags.push(buildDictTag(definition.dictionary)); +                    const tags = definition.tags.map(tag => dictTagBuild(tag, definition.tagMeta)); +                    tags.push(dictTagBuildSource(definition.dictionary));                      definitions.push({                          source: deinflection.source,                          reasons: deinflection.reasons, @@ -67,13 +67,13 @@ class Translator {                          expression: definition.expression,                          reading: definition.reading,                          glossary: definition.glossary, -                        tags: sortTags(tags) +                        tags: dictTagsSort(tags)                      });                  }              } -            definitions = undupeTermDefs(definitions); -            definitions = sortTermDefs(definitions, dictionaries); +            definitions = dictTermsUndupe(definitions); +            definitions = dictTermsSort(definitions, dictionaries);              let length = 0;              for (const definition of definitions) { @@ -86,7 +86,7 @@ class Translator {      findTermsGrouped(text, dictionaries, softKatakana) {          return this.findTerms(text, dictionaries, softKatakana).then(({length, definitions}) => { -            return {length, definitions: groupTermDefs(definitions, dictionaries)}; +            return {length, definitions: dictTermsGroup(definitions, dictionaries)};          });      } @@ -105,9 +105,9 @@ class Translator {          return Promise.all(promises).then(defSets => {              const definitions = defSets.reduce((a, b) => a.concat(b), []);              for (const definition of definitions) { -                const tags = definition.tags.map(tag => buildTag(tag, definition.tagMeta)); -                tags.push(buildDictTag(definition.dictionary)); -                definition.tags = sortTags(tags); +                const tags = definition.tags.map(tag => dictTagBuild(tag, definition.tagMeta)); +                tags.push(dictTagBuildSource(definition.dictionary)); +                definition.tags = dictTagsSort(tags);              }              return definitions; @@ -140,8 +140,8 @@ class Translator {      processKanji(definitions) {          for (const definition of definitions) { -            const tags = definition.tags.map(tag => buildTag(tag, definition.tagMeta)); -            definition.tags = sortTags(tags); +            const tags = definition.tags.map(tag => dictTagBuild(tag, definition.tagMeta)); +            definition.tags = dictTagsSort(tags);          }          return definitions; diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 852dfac7..7a8f15ef 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -17,27 +17,9 @@   */ -function helperKanjiLinks(options) { -    const isKanji = c => { -        const code = c.charCodeAt(0); -        return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; -    }; - -    let result = ''; -    for (const c of options.fn(this)) { -        if (isKanji(c)) { -            result += `<a href="#" class="kanji-link">${c}</a>`; -        } else { -            result += c; -        } -    } - -    return result; -} - -function helperMultiLine(options) { -    return options.fn(this).split('\n').join('<br>'); -} +/* + * Promise + */  function promiseCallback(promise, callback) {      return promise.then(result => { @@ -50,19 +32,175 @@ function promiseCallback(promise, callback) {      });  } -function getYomichan() { + +/* + * Instance + */ + +function instYomi() {      return chrome.extension.getBackgroundPage().yomichan;  } -function getDatabase() { -    return getYomichan().translator.database; +function instDb() { +    return instYomi().translator.database;  } -function getAnki() { -    return getYomichan().anki; +function instAnki() { +    return instYomi().anki;  } -function sortTermDefs(definitions, dictionaries=null) { + + +/* + * Options + */ + +function optionsSetDefaults(options) { +    const defaults = { +        general: { +            enable: true, +            audioPlayback: true, +            groupResults: true, +            softKatakana: true, +            maxResults: 32, +            showAdvanced: false +        }, + +        scanning: { +            requireShift: true, +            selectText: true, +            imposter: true, +            delay: 15, +            length: 10 +        }, + +        dictionaries: {}, + +        anki: { +            enable: false, +            server: 'http://127.0.0.1:8765', +            tags: ['yomichan'], +            htmlCards: true, +            sentenceExt: 200, +            terms: {deck: '', model: '', fields: {}}, +            kanji: {deck: '', model: '', fields: {}} +        } +    }; + +    const combine = (target, source) => { +        for (const key in source) { +            if (!target.hasOwnProperty(key)) { +                target[key] = source[key]; +            } +        } +    }; + +    combine(options, defaults); +    combine(options.general, defaults.general); +    combine(options.scanning, defaults.scanning); +    combine(options.anki, defaults.anki); +    combine(options.anki.terms, defaults.anki.terms); +    combine(options.anki.kanji, defaults.anki.kanji); + +    return options; +} + +function optionsVersion(options) { +    const fixups = [ +        () => { +            const copy = (targetDict, targetKey, sourceDict, sourceKey) => { +                targetDict[targetKey] = sourceDict.hasOwnProperty(sourceKey) ? sourceDict[sourceKey] : targetDict[targetKey]; +            }; + +            copy(options.general, 'autoStart', options, 'activateOnStartup'); +            copy(options.general, 'audioPlayback', options, 'enableAudioPlayback'); +            copy(options.general, 'softKatakana', options, 'enableSoftKatakanaSearch'); +            copy(options.general, 'groupResults', options, 'groupTermResults'); +            copy(options.general, 'showAdvanced', options, 'showAdvancedOptions'); + +            copy(options.scanning, 'requireShift', options, 'holdShiftToScan'); +            copy(options.scanning, 'selectText', options, 'selectMatchedText'); +            copy(options.scanning, 'delay', options, 'scanDelay'); +            copy(options.scanning, 'length', options, 'scanLength'); + +            options.anki.enable = options.ankiMethod === 'ankiconnect'; + +            copy(options.anki, 'tags', options, 'ankiCardTags'); +            copy(options.anki, 'sentenceExt', options, 'sentenceExtent'); +            copy(options.anki.terms, 'deck', options, 'ankiTermDeck'); +            copy(options.anki.terms, 'model', options, 'ankiTermModel'); +            copy(options.anki.terms, 'fields', options, 'ankiTermFields'); +            copy(options.anki.kanji, 'deck', options, 'ankiKanjiDeck'); +            copy(options.anki.kanji, 'model', options, 'ankiKanjiModel'); +            copy(options.anki.kanji, 'fields', options, 'ankiKanjiFields'); + +            for (const title in options.dictionaries) { +                const dictionary = options.dictionaries[title]; +                dictionary.enabled = dictionary.enableTerms || dictionary.enableKanji; +                dictionary.priority = 0; +            } +        }, +        () => { +            const fixupFields = fields => { +                const fixups = { +                    '{expression-furigana}': '{furigana}', +                    '{glossary-list}': '{glossary}' +                }; + +                for (const name in fields) { +                    for (const fixup in fixups) { +                        fields[name] = fields[name].replace(fixup, fixups[fixup]); +                    } +                } +            }; + +            fixupFields(options.anki.terms.fields); +            fixupFields(options.anki.kanji.fields); +        } +    ]; + +    optionsSetDefaults(options); +    if (!options.hasOwnProperty('version')) { +        options.version = fixups.length; +    } + +    while (options.version < fixups.length) { +        fixups[options.version++](); +    } + +    return options; +} + +function optionsLoad() { +    return new Promise((resolve, reject) => { +        chrome.storage.sync.get(null, options => resolve(optionsVersion(options))); +    }); +} + +function optionsSave(options) { +    return new Promise((resolve, reject) => { +        chrome.storage.sync.set(options, resolve); +    }); +} + + +/* + * Dictionary + */ + +function dictEnabled(options) { +    const dictionaries = {}; +    for (const title in options.dictionaries) { +        const dictionary = options.dictionaries[title]; +        if (dictionary.enabled) { +            dictionaries[title] = dictionary; +        } +    } + +    return dictionaries; +} + +function dictTermsSort(definitions, dictionaries=null) {      return definitions.sort((v1, v2) => {          const sl1 = v1.source.length;          const sl2 = v2.source.length; @@ -102,7 +240,7 @@ function sortTermDefs(definitions, dictionaries=null) {      });  } -function undupeTermDefs(definitions) { +function dictTermsUndupe(definitions) {      const definitionGroups = {};      for (const definition of definitions) {          const definitionExisting = definitionGroups[definition.id]; @@ -119,7 +257,7 @@ function undupeTermDefs(definitions) {      return definitionsUnique;  } -function groupTermDefs(definitions, dictionaries) { +function dictTermsGroup(definitions, dictionaries) {      const groups = {};      for (const definition of definitions) {          const key = [definition.source, definition.expression].concat(definition.reasons); @@ -139,7 +277,7 @@ function groupTermDefs(definitions, dictionaries) {      for (const key in groups) {          const groupDefs = groups[key];          const firstDef = groupDefs[0]; -        sortTermDefs(groupDefs, dictionaries); +        dictTermsSort(groupDefs, dictionaries);          results.push({              definitions: groupDefs,              expression: firstDef.expression, @@ -150,24 +288,24 @@ function groupTermDefs(definitions, dictionaries) {          });      } -    return sortTermDefs(results); +    return dictTermsSort(results);  } -function buildDictTag(name) { -    return sanitizeTag({name, category: 'dictionary', order: 100}); +function dictTagBuildSource(name) { +    return dictTagSanitize({name, category: 'dictionary', order: 100});  } -function buildTag(name, meta) { +function dictTagBuild(name, meta) {      const tag = {name};      const symbol = name.split(':')[0];      for (const prop in meta[symbol] || {}) {          tag[prop] = meta[symbol][prop];      } -    return sanitizeTag(tag); +    return dictTagSanitize(tag);  } -function sanitizeTag(tag) { +function dictTagSanitize(tag) {      tag.name = tag.name || 'untitled';      tag.category = tag.category || 'default';      tag.notes = tag.notes || ''; @@ -175,11 +313,7 @@ function sanitizeTag(tag) {      return tag;  } -function splitField(field) { -    return field.length === 0 ? [] : field.split(' '); -} - -function sortTags(tags) { +function dictTagsSort(tags) {      return tags.sort((v1, v2) => {          const order1 = v1.order;          const order2 = v2.order; @@ -201,7 +335,11 @@ function sortTags(tags) {      });  } -function formatField(field, definition, mode, options) { +function dictFieldSplit(field) { +    return field.length === 0 ? [] : field.split(' '); +} + +function dictFieldFormat(field, definition, mode, options) {      const markers = [          'audio',          'character', @@ -237,7 +375,12 @@ function formatField(field, definition, mode, options) {      return field;  } -function loadJson(url) { + +/* + * Json + */ + +function jsonLoad(url) {      return new Promise((resolve, reject) => {          const xhr = new XMLHttpRequest();          xhr.overrideMimeType('application/json'); @@ -255,13 +398,13 @@ function loadJson(url) {      });  } -function loadJsonInt(url) { -    return loadJson(chrome.extension.getURL(url)); +function jsonLoadInt(url) { +    return jsonLoad(chrome.extension.getURL(url));  } -function importJsonDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded) { +function jsonLoadDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded) {      const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); -    return loadJson(indexUrl).then(index => { +    return jsonLoad(indexUrl).then(index => {          if (!index.title || !index.version || !index.revision) {              return Promise.reject('unrecognized dictionary format');          } @@ -285,7 +428,7 @@ function importJsonDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded) {          for (let i = 1; i <= index.termBanks; ++i) {              const bankUrl = `${indexDir}/term_bank_${i}.json`; -            loaders.push(() => loadJson(bankUrl).then(entries => termsLoaded( +            loaders.push(() => jsonLoad(bankUrl).then(entries => termsLoaded(                  index.title,                  entries,                  banksTotal, @@ -295,7 +438,7 @@ function importJsonDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded) {          for (let i = 1; i <= index.kanjiBanks; ++i) {              const bankUrl = `${indexDir}/kanji_bank_${i}.json`; -            loaders.push(() => loadJson(bankUrl).then(entries => kanjiLoaded( +            loaders.push(() => jsonLoad(bankUrl).then(entries => kanjiLoaded(                  index.title,                  entries,                  banksTotal, @@ -311,3 +454,30 @@ function importJsonDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded) {          return chain;      });  } + + +/* + * Helpers + */ + +function helperKanjiLinks(options) { +    const isKanji = c => { +        const code = c.charCodeAt(0); +        return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; +    }; + +    let result = ''; +    for (const c of options.fn(this)) { +        if (isKanji(c)) { +            result += `<a href="#" class="kanji-link">${c}</a>`; +        } else { +            result += c; +        } +    } + +    return result; +} + +function helperMultiLine(options) { +    return options.fn(this).split('\n').join('<br>'); +} diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index a544d0ad..abf6c10c 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -115,7 +115,7 @@ class Yomichan {          }          for (const name in fields) { -            note.fields[name] = formatField( +            note.fields[name] = dictFieldFormat(                  fields[name],                  definition,                  mode, @@ -132,7 +132,7 @@ class Yomichan {      api_findKanji({text, callback}) {          promiseCallback( -            this.translator.findKanji(text, optionsEnabledDicts(this.options)).then(definitions => { +            this.translator.findKanji(text, dictEnabled(this.options)).then(definitions => {                  return definitions.slice(0, this.options.general.maxResults);              }),              callback @@ -141,7 +141,7 @@ class Yomichan {      api_findTerms({text, callback}) {          promiseCallback( -            this.translator.findTerms(text, optionsEnabledDicts(this.options), this.options.general.softKatakana).then(({definitions, length}) => { +            this.translator.findTerms(text, dictEnabled(this.options), this.options.general.softKatakana).then(({definitions, length}) => {                  return {length, definitions: definitions.slice(0, this.options.general.maxResults)};              }),              callback @@ -150,7 +150,7 @@ class Yomichan {      api_findTermsGrouped({text, callback}) {          promiseCallback( -            this.translator.findTermsGrouped(text, optionsEnabledDicts(this.options), this.options.general.softKatakana).then(({definitions, length}) => { +            this.translator.findTermsGrouped(text, dictEnabled(this.options), this.options.general.softKatakana).then(({definitions, length}) => {                  return {length, definitions: definitions.slice(0, this.options.general.maxResults)};              }),              callback diff --git a/ext/bg/options.html b/ext/bg/options.html index 8bf773b0..7739c540 100644 --- a/ext/bg/options.html +++ b/ext/bg/options.html @@ -240,6 +240,5 @@          <script src="js/gecko.js"></script>          <script src="js/util.js"></script>          <script src="js/options.js"></script> -        <script src="js/options-form.js"></script>      </body>  </html> |