aboutsummaryrefslogtreecommitdiff
path: root/ext/bg/js/options-form.js
diff options
context:
space:
mode:
authorAlex Yatskov <alex@foosoft.net>2016-12-22 18:50:58 -0800
committerAlex Yatskov <alex@foosoft.net>2016-12-22 18:50:58 -0800
commit39fa11f72bae62985ee5b27103e5959dab30316c (patch)
treee7fe89d18a2b0bfa892ede044d7e6dcc076bbf7b /ext/bg/js/options-form.js
parent5710dc55a73491a0be2259fbd21874bddda54877 (diff)
parent9d21f8a456530c29c7c03db4896562a4902f6f8a (diff)
Merge branch 'dev'
Diffstat (limited to 'ext/bg/js/options-form.js')
-rw-r--r--ext/bg/js/options-form.js470
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);
- });
-});