diff options
Diffstat (limited to 'ext/bg/js/options-form.js')
-rw-r--r-- | ext/bg/js/options-form.js | 470 |
1 files changed, 321 insertions, 149 deletions
diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js index eb562142..fb81e83a 100644 --- a/ext/bg/js/options-form.js +++ b/ext/bg/js/options-form.js @@ -16,55 +16,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +// +// General +// function yomichan() { return chrome.extension.getBackgroundPage().yomichan; } -function anki() { - return yomichan().anki; -} - -function fieldsToDict(selection) { - const result = {}; - selection.each((index, element) => { - result[$(element).data('field')] = $(element).val(); - }); - - return result; -} - -function modelIdToFieldOptKey(id) { - return { - 'anki-term-model': 'ankiTermFields', - 'anki-kanji-model': 'ankiKanjiFields' - }[id]; -} - -function modelIdToMarkers(id) { - return { - 'anki-term-model': [ - 'audio', - 'expression', - 'expression-furigana', - 'glossary', - 'glossary-list', - 'reading', - 'sentence', - 'tags', - 'url' - ], - 'anki-kanji-model': [ - 'character', - 'glossary', - 'glossary-list', - 'kunyomi', - 'onyomi', - 'url' - ], - }[id]; -} - function getFormValues() { return loadOptions().then(optsOld => { const optsNew = $.extend({}, optsOld); @@ -91,6 +50,14 @@ function getFormValues() { optsNew.ankiKanjiModel = $('#anki-kanji-model').val(); optsNew.ankiKanjiFields = fieldsToDict($('#kanji .anki-field-value')); + $('.dict-group').each((index, element) => { + const dictionary = $(element); + const title = dictionary.data('title'); + const enableTerms = dictionary.find('.dict-enable-terms').prop('checked'); + const enableKanji = dictionary.find('.dict-enable-kanji').prop('checked'); + optsNew.dictionaries[title] = {enableTerms, enableKanji}; + }); + return { optsNew: sanitizeOptions(optsNew), optsOld: sanitizeOptions(optsOld) @@ -120,43 +87,294 @@ function updateVisibility(opts) { } } -function populateAnkiDeckAndModel(opts) { - const ankiSpinner = $('#anki-spinner'); - ankiSpinner.show(); +$(document).ready(() => { + Handlebars.partials = Handlebars.templates; + + loadOptions().then(opts => { + $('#activate-on-startup').prop('checked', opts.activateOnStartup); + $('#enable-audio-playback').prop('checked', opts.enableAudioPlayback); + $('#enable-soft-katakana-search').prop('checked', opts.enableSoftKatakanaSearch); + $('#show-advanced-options').prop('checked', opts.showAdvancedOptions); + + $('#hold-shift-to-scan').prop('checked', opts.holdShiftToScan); + $('#select-matched-text').prop('checked', opts.selectMatchedText); + $('#scan-delay').val(opts.scanDelay); + $('#scan-length').val(opts.scanLength); + + $('#anki-method').val(opts.ankiMethod); + $('#anki-username').val(opts.ankiUsername); + $('#anki-password').val(opts.ankiPassword); + $('#anki-card-tags').val(opts.ankiCardTags.join(' ')); + $('#sentence-extent').val(opts.sentenceExtent); + + $('input, select').not('.anki-model').change(onOptionsChanged); + $('.anki-model').change(onAnkiModelChanged); + + $('#dict-purge').click(onDictionaryPurge); + $('#dict-importer a').click(onDictionarySetUrl); + $('#dict-import').click(onDictionaryImport); + $('#dict-url').on('input', onDictionaryUpdateUrl); - const ankiFormat = $('#anki-format'); - ankiFormat.hide(); + populateDictionaries(opts); + populateAnkiDeckAndModel(opts); + updateVisibility(opts); + }); +}); - const ankiDeck = $('.anki-deck'); - ankiDeck.find('option').remove(); +// +// Dictionary +// - const ankiModel = $('.anki-model'); - ankiModel.find('option').remove(); +function database() { + return yomichan().translator.database; +} - return anki().getDeckNames().then(names => { - names.forEach(name => ankiDeck.append($('<option/>', {value: name, text: name}))); - $('#anki-term-deck').val(opts.ankiTermDeck); - $('#anki-kanji-deck').val(opts.ankiKanjiDeck); +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(opts) { + showDictionaryError(null); + showDictionarySpinner(true); + + const dictGroups = $('#dict-groups').empty(); + const dictWarning = $('#dict-warning').hide(); + + let dictCount = 0; + return database().getDictionaries().then(rows => { + rows.forEach(row => { + const dictOpts = opts.dictionaries[row.title] || {enableTerms: false, enableKanji: false}; + const html = Handlebars.templates['dictionary.html']({ + title: row.title, + version: row.version, + hasTerms: row.hasTerms, + hasKanji: row.hasKanji, + enableTerms: dictOpts.enableTerms, + enableKanji: dictOpts.enableKanji + }); + + dictGroups.append($(html)); + ++dictCount; + }); + + $('.dict-enable-terms, .dict-enable-kanji').change(onOptionsChanged); + $('.dict-delete').click(onDictionaryDelete); + }).catch(error => { + showDictionaryError(error); }).then(() => { - return anki().getModelNames(); - }).then(names => { - names.forEach(name => ankiModel.append($('<option/>', {value: name, text: name}))); - return populateAnkiFields($('#anki-term-model').val(opts.ankiTermModel), opts); + 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 database().purge().catch(error => { + showDictionaryError(error); + }).then(() => { + showDictionarySpinner(false); + dictControls.show(); + dictProgress.hide(); + return loadOptions().then(opts => populateDictionaries(opts)); + }); +} + +function onDictionaryDelete() { + showDictionaryError(null); + showDictionarySpinner(true); + + const dictGroup = $(this).closest('.dict-group'); + const dictProgress = dictGroup.find('.dict-delete-progress').show(); + const dictControls = dictGroup.find('.dict-group-controls').hide(); + const setProgress = percent => { + dictProgress.find('.progress-bar').css('width', `${percent}%`); + }; + + setProgress(0.0); + + database().deleteDictionary(dictGroup.data('title'), (total, current) => setProgress(current / total * 100.0)).catch(error => { + showDictionaryError(error); }).then(() => { - return populateAnkiFields($('#anki-kanji-model').val(opts.ankiKanjiModel), opts); + showDictionarySpinner(false); + dictProgress.hide(); + dictControls.show(); + return loadOptions().then(opts => populateDictionaries(opts)); + }); +} + +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); + + loadOptions().then(opts => { + database().importDictionary(dictUrl.val(), (total, current) => setProgress(current / total * 100.0)).then(summary => { + opts.dictionaries[summary.title] = {enableTerms: summary.hasTerms, enableKanji: summary.hasKanji}; + return saveOptions(opts).then(() => yomichan().setOptions(opts)); + }).then(() => { + return populateDictionaries(opts); + }).catch(error => { + showDictionaryError(error); + }).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/data/${url}/index.json`)); + } + + dictUrl.trigger('input'); +} + +function onDictionaryUpdateUrl() { + $('#dict-import').prop('disabled', $(this).val().length === 0); +} + +// +// Anki +// + +function anki() { + return yomichan().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 fieldsToDict(selection) { + const result = {}; + selection.each((index, element) => { + result[$(element).data('field')] = $(element).val(); + }); + + return result; +} + +function modelIdToFieldOptKey(id) { + return { + 'anki-term-model': 'ankiTermFields', + 'anki-kanji-model': 'ankiKanjiFields' + }[id]; +} + +function modelIdToMarkers(id) { + return { + 'anki-term-model': [ + 'audio', + 'expression', + 'expression-furigana', + 'glossary', + 'glossary-list', + 'reading', + 'sentence', + 'tags', + 'url' + ], + 'anki-kanji-model': [ + 'character', + 'glossary', + 'glossary-list', + 'kunyomi', + 'onyomi', + 'url' + ], + }[id]; +} + +function populateAnkiDeckAndModel(opts) { + showAnkiError(null); + showAnkiSpinner(true); + + const ankiFormat = $('#anki-format').hide(); + + return Promise.all([anki().getDeckNames(), anki().getModelNames()]).then(([deckNames, modelNames]) => { + const ankiDeck = $('.anki-deck'); + ankiDeck.find('option').remove(); + deckNames.forEach(name => ankiDeck.append($('<option/>', {value: name, text: name}))); + + $('#anki-term-deck').val(opts.ankiTermDeck); + $('#anki-kanji-deck').val(opts.ankiKanjiDeck); + + const ankiModel = $('.anki-model'); + ankiModel.find('option').remove(); + modelNames.forEach(name => ankiModel.append($('<option/>', {value: name, text: name}))); + + return Promise.all([ + populateAnkiFields($('#anki-term-model').val(opts.ankiTermModel), opts), + populateAnkiFields($('#anki-kanji-model').val(opts.ankiKanjiModel), opts) + ]); }).then(() => { - $('#anki-error').hide(); ankiFormat.show(); }).catch(error => { - $('#anki-error').show().find('span').text(error); + showAnkiError(error); }).then(() => { - ankiSpinner.hide(); + showAnkiSpinner(false); }); } function populateAnkiFields(element, opts) { - const table = element.closest('.tab-pane').find('.anki-fields'); - table.find('tbody').remove(); + const tab = element.closest('.tab-pane'); + const container = tab.find('tbody').empty(); const modelName = element.val(); if (modelName === null) { @@ -168,41 +386,37 @@ function populateAnkiFields(element, opts) { const markers = modelIdToMarkers(modelId); return anki().getModelFieldNames(modelName).then(names => { - const tbody = $('<tbody>'); names.forEach(name => { - const button = $('<button>', {type: 'button', class: 'btn btn-default dropdown-toggle'}); - button.attr('data-toggle', 'dropdown').dropdown(); - - const markerItems = $('<ul>', {class: 'dropdown-menu dropdown-menu-right'}); - for (const marker of markers) { - const link = $('<a>', {href: '#'}).text(`{${marker}}`); - link.click(e => { - e.preventDefault(); - link.closest('.input-group').find('.anki-field-value').val(link.text()).trigger('change'); - }); - markerItems.append($('<li>').append(link)); - } + const html = Handlebars.templates['model.html']({name, markers, value: opts[optKey][name] || ''}); + container.append($(html)); + }); - const groupBtn = $('<div>', {class: 'input-group-btn'}); - groupBtn.append(button.append($('<span>', {class: 'caret'}))); - groupBtn.append(markerItems); + 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'); + }); + }); +} - const group = $('<div>', {class: 'input-group'}); - group.append($('<input>', { - type: 'text', - class: 'anki-field-value form-control', - value: opts[optKey][name] || '' - }).data('field', name).change(onOptionsChanged)); - group.append(groupBtn); +function onAnkiModelChanged(e) { + if (!e.originalEvent) { + return; + } - const row = $('<tr>'); - row.append($('<td>', {class: 'col-sm-2'}).text(name)); - row.append($('<td>', {class: 'col-sm-10'}).append(group)); + showAnkiError(null); + showAnkiSpinner(true); - tbody.append(row); + getFormValues().then(({optsNew, optsOld}) => { + optsNew[modelIdToFieldOptKey($(this).id)] = {}; + populateAnkiFields($(this), optsNew).then(() => { + saveOptions(optsNew).then(() => yomichan().setOptions(optsNew)); + }).catch(error => { + showAnkiError(error); + }).then(() => { + showAnkiSpinner(false); }); - - table.append(tbody); }); } @@ -212,7 +426,7 @@ function onOptionsChanged(e) { } getFormValues().then(({optsNew, optsOld}) => { - saveOptions(optsNew).then(() => { + return saveOptions(optsNew).then(() => { yomichan().setOptions(optsNew); updateVisibility(optsNew); @@ -221,60 +435,18 @@ function onOptionsChanged(e) { optsNew.ankiPassword !== optsOld.ankiPassword; if (loginChanged && optsNew.ankiMethod === 'ankiweb') { - anki().logout().then(() => populateAnkiDeckAndModel(optsNew)).catch(error => { - $('#anki-error').show().find('span').text(error); - }); + showAnkiError(null); + showAnkiSpinner(true); + return anki().logout().then(() => populateAnkiDeckAndModel(optsNew)); } else if (loginChanged || optsNew.ankiMethod !== optsOld.ankiMethod) { - populateAnkiDeckAndModel(optsNew); + showAnkiError(null); + showAnkiSpinner(true); + return populateAnkiDeckAndModel(optsNew); } }); + }).catch(error => { + showAnkiError(error); + }).then(() => { + showAnkiSpinner(false); }); } - -function onAnkiModelChanged(e) { - if (!e.originalEvent) { - return; - } - - getFormValues().then(({optsNew, optsOld}) => { - optsNew[modelIdToFieldOptKey($(this).id)] = {}; - - const ankiSpinner = $('#anki-spinner'); - ankiSpinner.show(); - - populateAnkiFields($(this), optsNew).then(() => { - saveOptions(optsNew).then(() => yomichan().setOptions(optsNew)); - }).catch(error => { - $('#anki-error').show().find('span').text(error); - }).then(() => { - $('#anki-error').hide(); - ankiSpinner.hide(); - }); - }); -} - -$(document).ready(() => { - loadOptions().then(opts => { - $('#activate-on-startup').prop('checked', opts.activateOnStartup); - $('#enable-audio-playback').prop('checked', opts.enableAudioPlayback); - $('#enable-soft-katakana-search').prop('checked', opts.enableSoftKatakanaSearch); - $('#show-advanced-options').prop('checked', opts.showAdvancedOptions); - - $('#hold-shift-to-scan').prop('checked', opts.holdShiftToScan); - $('#select-matched-text').prop('checked', opts.selectMatchedText); - $('#scan-delay').val(opts.scanDelay); - $('#scan-length').val(opts.scanLength); - - $('#anki-method').val(opts.ankiMethod); - $('#anki-username').val(opts.ankiUsername); - $('#anki-password').val(opts.ankiPassword); - $('#anki-card-tags').val(opts.ankiCardTags.join(' ')); - $('#sentence-extent').val(opts.sentenceExtent); - - $('input, select').not('.anki-model').change(onOptionsChanged); - $('.anki-model').change(onAnkiModelChanged); - - populateAnkiDeckAndModel(opts); - updateVisibility(opts); - }); -}); |