diff options
Diffstat (limited to 'ext/bg/js')
| -rw-r--r-- | ext/bg/js/anki-note-builder.js | 110 | ||||
| -rw-r--r-- | ext/bg/js/backend.js | 9 | ||||
| -rw-r--r-- | ext/bg/js/dictionary.js | 88 | ||||
| -rw-r--r-- | ext/bg/js/settings/anki-templates.js | 8 | 
4 files changed, 120 insertions, 95 deletions
| 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 <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 <https://www.gnu.org/licenses/>. + */ + +/*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 <https://www.gnu.org/licenses/>.   */ -/*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); |