From 2e0b3a6ccc50eae3b86e8cc82c623d95a9defdaf Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 25 Feb 2020 20:38:18 -0500 Subject: Refactor dictNoteFormat --- ext/bg/js/dictionary.js | 57 ++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) (limited to 'ext/bg/js/dictionary.js') diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index f5c5b21b..7b112381 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -388,40 +388,39 @@ dictFieldFormat.markers = new Set([ ]); async function dictNoteFormat(definition, mode, options, templates) { - const note = {fields: {}, tags: options.anki.tags}; - let fields = []; - - if (mode === 'kanji') { - fields = options.anki.kanji.fields; - note.deckName = options.anki.kanji.deck; - note.modelName = options.anki.kanji.model; - } else { - fields = options.anki.terms.fields; - note.deckName = options.anki.terms.deck; - note.modelName = options.anki.terms.model; - - if (definition.audio) { - const audio = { - url: definition.audio.url, - filename: definition.audio.filename, - skipHash: '7e2c2f954ef6051373ba916f000168dc', - fields: [] - }; + const isKanji = (mode === 'kanji'); + const tags = options.anki.tags; + const modeOptions = isKanji ? options.anki.kanji : options.anki.terms; + const modeOptionsFieldEntries = Object.entries(modeOptions.fields); + + const note = { + fields: {}, + tags, + deckName: modeOptions.deck, + modelName: modeOptions.model + }; - for (const name in fields) { - if (fields[name].includes('{audio}')) { - audio.fields.push(name); - } - } + for (const [fieldName, fieldValue] of modeOptionsFieldEntries) { + note.fields[fieldName] = await dictFieldFormat(fieldValue, definition, mode, options, templates); + } - if (audio.fields.length > 0) { - note.audio = audio; + if (!isKanji && definition.audio) { + const audioFields = []; + + for (const [fieldName, fieldValue] of modeOptionsFieldEntries) { + if (fieldValue.includes('{audio}')) { + audioFields.push(fieldName); } } - } - for (const name in fields) { - note.fields[name] = await dictFieldFormat(fields[name], definition, mode, options, templates); + if (audioFields.length > 0) { + note.audio = { + url: definition.audio.url, + filename: definition.audio.filename, + skipHash: '7e2c2f954ef6051373ba916f000168dc', + fields: audioFields + }; + } } return note; -- cgit v1.2.3 From 0b5a26e64a3fecf4ab64e5a1b6a1b068cde695fe Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 25 Feb 2020 22:10:49 -0500 Subject: Update dictEnabledSet and dictConfigured to use for of --- ext/bg/js/dictionary.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'ext/bg/js/dictionary.js') diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 7b112381..ffeac80a 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -20,22 +20,16 @@ function dictEnabledSet(options) { const enabledDictionaryMap = new Map(); - const optionsDictionaries = options.dictionaries; - for (const title in optionsDictionaries) { - if (!hasOwn(optionsDictionaries, title)) { continue; } - const dictionary = optionsDictionaries[title]; - if (!dictionary.enabled) { continue; } - enabledDictionaryMap.set(title, { - priority: dictionary.priority || 0, - allowSecondarySearches: !!dictionary.allowSecondarySearches - }); + for (const [title, {enabled, priority, allowSecondarySearches}] of Object.entries(options.dictionaries)) { + if (!enabled) { continue; } + enabledDictionaryMap.set(title, {priority, allowSecondarySearches}); } return enabledDictionaryMap; } function dictConfigured(options) { - for (const title in options.dictionaries) { - if (options.dictionaries[title].enabled) { + for (const {enabled} of Object.values(options.dictionaries)) { + if (enabled) { return true; } } -- cgit v1.2.3 From 69cce49b0d5d9f11f4ffb529ae3d060536297c07 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 7 Mar 2020 15:14:05 -0500 Subject: Move Anki note generation functionality into a new class --- ext/bg/background.html | 1 + ext/bg/js/anki-note-builder.js | 110 +++++++++++++++++++++++++++++++++++ ext/bg/js/backend.js | 9 +-- ext/bg/js/dictionary.js | 88 ---------------------------- ext/bg/js/settings/anki-templates.js | 8 ++- ext/bg/settings.html | 1 + 6 files changed, 122 insertions(+), 95 deletions(-) create mode 100644 ext/bg/js/anki-note-builder.js (limited to 'ext/bg/js/dictionary.js') diff --git a/ext/bg/background.html b/ext/bg/background.html index f2f70d4d..8db017f1 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -22,6 +22,7 @@ + diff --git a/ext/bg/js/anki-note-builder.js b/ext/bg/js/anki-note-builder.js new file mode 100644 index 00000000..f7555280 --- /dev/null +++ b/ext/bg/js/anki-note-builder.js @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 Alex Yatskov + * Author: Alex Yatskov + * + * 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 . + */ + +/*global apiTemplateRender*/ + +class AnkiNoteBuilder { + constructor() { + this._markers = new Set([ + 'audio', + 'character', + 'cloze-body', + 'cloze-prefix', + 'cloze-suffix', + 'dictionary', + 'expression', + 'furigana', + 'furigana-plain', + 'glossary', + 'glossary-brief', + 'kunyomi', + 'onyomi', + 'reading', + 'screenshot', + 'sentence', + 'tags', + 'url' + ]); + } + + async createNote(definition, mode, options, templates) { + const isKanji = (mode === 'kanji'); + const tags = options.anki.tags; + const modeOptions = isKanji ? options.anki.kanji : options.anki.terms; + const modeOptionsFieldEntries = Object.entries(modeOptions.fields); + + const note = { + fields: {}, + tags, + deckName: modeOptions.deck, + modelName: modeOptions.model + }; + + for (const [fieldName, fieldValue] of modeOptionsFieldEntries) { + note.fields[fieldName] = await this.formatField(fieldValue, definition, mode, options, templates, null); + } + + if (!isKanji && definition.audio) { + const audioFields = []; + + for (const [fieldName, fieldValue] of modeOptionsFieldEntries) { + if (fieldValue.includes('{audio}')) { + audioFields.push(fieldName); + } + } + + if (audioFields.length > 0) { + note.audio = { + url: definition.audio.url, + filename: definition.audio.filename, + skipHash: '7e2c2f954ef6051373ba916f000168dc', // hash of audio data that should be skipped + fields: audioFields + }; + } + } + + return note; + } + + async formatField(field, definition, mode, options, templates, errors=null) { + const data = { + marker: null, + definition, + group: options.general.resultOutputMode === 'group', + merge: options.general.resultOutputMode === 'merge', + modeTermKanji: mode === 'term-kanji', + modeTermKana: mode === 'term-kana', + modeKanji: mode === 'kanji', + compactGlossaries: options.general.compactGlossaries + }; + const markers = this._markers; + const pattern = /\{([\w-]+)\}/g; + return await stringReplaceAsync(field, pattern, async (g0, marker) => { + if (!markers.has(marker)) { + return g0; + } + data.marker = marker; + try { + return await apiTemplateRender(templates, data); + } catch (e) { + if (errors) { errors.push(e); } + return `{${marker}-render-error}`; + } + }); + } +} diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 60a87916..929281da 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -20,10 +20,10 @@ conditionsTestValue, profileConditionsDescriptor handlebarsRenderDynamic requestText, requestJson, optionsLoad -dictConfigured, dictTermsSort, dictEnabledSet, dictNoteFormat +dictConfigured, dictTermsSort, dictEnabledSet audioGetUrl, audioInject jpConvertReading, jpDistributeFuriganaInflected, jpKatakanaToHiragana -AudioSystem, Translator, AnkiConnect, AnkiNull, Mecab, BackendApiForwarder, JsonSchema, ClipboardMonitor*/ +AnkiNoteBuilder, AudioSystem, Translator, AnkiConnect, AnkiNull, Mecab, BackendApiForwarder, JsonSchema, ClipboardMonitor*/ class Backend { constructor() { @@ -31,6 +31,7 @@ class Backend { this.anki = new AnkiNull(); this.mecab = new Mecab(); this.clipboardMonitor = new ClipboardMonitor({getClipboard: this._onApiClipboardGet.bind(this)}); + this.ankiNoteBuilder = new AnkiNoteBuilder(); this.options = null; this.optionsSchema = null; this.defaultAnkiFieldTemplates = null; @@ -450,7 +451,7 @@ class Backend { ); } - const note = await dictNoteFormat(definition, mode, options, templates); + const note = await this.ankiNoteBuilder.createNote(definition, mode, options, templates); return this.anki.addNote(note); } @@ -463,7 +464,7 @@ class Backend { const notes = []; for (const definition of definitions) { for (const mode of modes) { - const note = await dictNoteFormat(definition, mode, options, templates); + const note = await this.ankiNoteBuilder.createNote(definition, mode, options, templates); notes.push(note); } } diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index ffeac80a..3dd1d0c1 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -/*global apiTemplateRender*/ - function dictEnabledSet(options) { const enabledDictionaryMap = new Map(); for (const [title, {enabled, priority, allowSecondarySearches}] of Object.entries(options.dictionaries)) { @@ -333,89 +331,3 @@ function dictTagsSort(tags) { function dictFieldSplit(field) { return field.length === 0 ? [] : field.split(' '); } - -async function dictFieldFormat(field, definition, mode, options, templates, exceptions) { - const data = { - marker: null, - definition, - group: options.general.resultOutputMode === 'group', - merge: options.general.resultOutputMode === 'merge', - modeTermKanji: mode === 'term-kanji', - modeTermKana: mode === 'term-kana', - modeKanji: mode === 'kanji', - compactGlossaries: options.general.compactGlossaries - }; - const markers = dictFieldFormat.markers; - const pattern = /\{([\w-]+)\}/g; - return await stringReplaceAsync(field, pattern, async (g0, marker) => { - if (!markers.has(marker)) { - return g0; - } - data.marker = marker; - try { - return await apiTemplateRender(templates, data); - } catch (e) { - if (exceptions) { exceptions.push(e); } - return `{${marker}-render-error}`; - } - }); -} -dictFieldFormat.markers = new Set([ - 'audio', - 'character', - 'cloze-body', - 'cloze-prefix', - 'cloze-suffix', - 'dictionary', - 'expression', - 'furigana', - 'furigana-plain', - 'glossary', - 'glossary-brief', - 'kunyomi', - 'onyomi', - 'reading', - 'screenshot', - 'sentence', - 'tags', - 'url' -]); - -async function dictNoteFormat(definition, mode, options, templates) { - const isKanji = (mode === 'kanji'); - const tags = options.anki.tags; - const modeOptions = isKanji ? options.anki.kanji : options.anki.terms; - const modeOptionsFieldEntries = Object.entries(modeOptions.fields); - - const note = { - fields: {}, - tags, - deckName: modeOptions.deck, - modelName: modeOptions.model - }; - - for (const [fieldName, fieldValue] of modeOptionsFieldEntries) { - note.fields[fieldName] = await dictFieldFormat(fieldValue, definition, mode, options, templates); - } - - if (!isKanji && definition.audio) { - const audioFields = []; - - for (const [fieldName, fieldValue] of modeOptionsFieldEntries) { - if (fieldValue.includes('{audio}')) { - audioFields.push(fieldName); - } - } - - if (audioFields.length > 0) { - note.audio = { - url: definition.audio.url, - filename: definition.audio.filename, - skipHash: '7e2c2f954ef6051373ba916f000168dc', - fields: audioFields - }; - } - } - - return note; -} diff --git a/ext/bg/js/settings/anki-templates.js b/ext/bg/js/settings/anki-templates.js index 244ec42e..32a990f9 100644 --- a/ext/bg/js/settings/anki-templates.js +++ b/ext/bg/js/settings/anki-templates.js @@ -17,8 +17,9 @@ */ /*global getOptionsContext, getOptionsMutable, settingsSaveOptions -ankiGetFieldMarkers, ankiGetFieldMarkersHtml, dictFieldFormat -apiOptionsGet, apiTermsFind, apiGetDefaultAnkiFieldTemplates*/ +ankiGetFieldMarkers, ankiGetFieldMarkersHtml +apiOptionsGet, apiTermsFind, apiGetDefaultAnkiFieldTemplates, +AnkiNoteBuilder*/ function onAnkiFieldTemplatesReset(e) { e.preventDefault(); @@ -92,7 +93,8 @@ async function ankiTemplatesValidate(infoNode, field, mode, showSuccessResult, i const options = await apiOptionsGet(optionsContext); let templates = options.anki.fieldTemplates; if (typeof templates !== 'string') { templates = await apiGetDefaultAnkiFieldTemplates(); } - result = await dictFieldFormat(field, definition, mode, options, templates, exceptions); + const ankiNoteBuilder = new AnkiNoteBuilder(); + result = await ankiNoteBuilder.formatField(field, definition, mode, options, templates, exceptions); } } catch (e) { exceptions.push(e); diff --git a/ext/bg/settings.html b/ext/bg/settings.html index e9fc6be5..0db76d71 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -1090,6 +1090,7 @@ + -- cgit v1.2.3