diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-09-10 18:03:46 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-09-10 18:03:46 -0400 | 
| commit | a531618c48481a30d63112cf59b7806291f0bda4 (patch) | |
| tree | 04b185c11406952a179ee229e39847234d592ea4 /ext/mixed/js | |
| parent | 9ce682272c5d665bbbe9cbd1380416c3d22f9b04 (diff) | |
Use Anki classes directly in Display (#804)
* Add _getTemplates function
* Add template renderer to display pages
* Add AnkiNoteBuilder to Display
* Update AnkiTemplatesController to directly use TemplateRenderer
* Remove old APIs
Diffstat (limited to 'ext/mixed/js')
| -rw-r--r-- | ext/mixed/js/api.js | 12 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 128 | 
2 files changed, 115 insertions, 25 deletions
| diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index 4a1b0c11..1e7625da 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -89,22 +89,10 @@ const api = (() => {              return this._invoke('injectAnkiNoteMedia', {expression, reading, timestamp, audioDetails, screenshotDetails, clipboardImage});          } -        definitionAdd(definition, mode, context, ownerFrameId, optionsContext) { -            return this._invoke('definitionAdd', {definition, mode, context, ownerFrameId, optionsContext}); -        } - -        definitionsAddable(definitions, modes, context, optionsContext) { -            return this._invoke('definitionsAddable', {definitions, modes, context, optionsContext}); -        } -          noteView(noteId) {              return this._invoke('noteView', {noteId});          } -        templateRender(template, data, marker) { -            return this._invoke('templateRender', {data, template, marker}); -        } -          audioGetUri(source, expression, reading, details) {              return this._invoke('audioGetUri', {source, expression, reading, details});          } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 7dd5920a..4c42a48d 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -16,6 +16,7 @@   */  /* global + * AnkiNoteBuilder   * AudioSystem   * DisplayGenerator   * DisplayHistory @@ -24,6 +25,7 @@   * MediaLoader   * PopupFactory   * QueryParser + * TemplateRenderer   * WindowScroll   * api   * dynamicLoader @@ -83,6 +85,12 @@ class Display extends EventDispatcher {          });          this._mode = null;          this._ownerFrameId = null; +        this._defaultAnkiFieldTemplates = null; +        this._defaultAnkiFieldTemplatesPromise = null; +        this._templateRenderer = new TemplateRenderer(); +        this._ankiNoteBuilder = new AnkiNoteBuilder({ +            renderTemplate: this._renderTemplate.bind(this) +        });          this.registerActions([              ['close',            () => { this.onEscape(); }], @@ -891,7 +899,8 @@ class Display extends EventDispatcher {          const modes = isTerms ? ['term-kanji', 'term-kana'] : ['kanji'];          let states;          try { -            states = await this._getDefinitionsAddable(definitions, modes); +            const noteContext = await this._getNoteContext(); +            states = await this._areDefinitionsAddable(definitions, modes, noteContext);          } catch (e) {              return;          } @@ -1054,10 +1063,8 @@ class Display extends EventDispatcher {          try {              this.setSpinnerVisible(true); -            const ownerFrameId = this._ownerFrameId; -            const optionsContext = this.getOptionsContext();              const noteContext = await this._getNoteContext(); -            const noteId = await api.definitionAdd(definition, mode, noteContext, ownerFrameId, optionsContext); +            const noteId = await this._addDefinition(definition, mode, noteContext);              if (noteId) {                  const index = this._definitions.indexOf(definition);                  const adderButton = this._adderButtonFind(index, mode); @@ -1196,15 +1203,6 @@ class Display extends EventDispatcher {          return container !== null ? container.querySelector('.action-play-audio>img') : null;      } -    async _getDefinitionsAddable(definitions, modes) { -        try { -            const noteContext = await this._getNoteContext(); -            return await api.definitionsAddable(definitions, modes, noteContext, this.getOptionsContext()); -        } catch (e) { -            return []; -        } -    } -      _indexOf(nodeList, node) {          for (let i = 0, ii = nodeList.length; i < ii; ++i) {              if (nodeList[i] === node) { @@ -1315,4 +1313,108 @@ class Display extends EventDispatcher {          this._mode = mode;          this.trigger('modeChange', {mode});      } + +    async _getTemplates(options) { +        let templates = options.anki.fieldTemplates; +        if (typeof templates === 'string') { return templates; } + +        templates = this._defaultAnkiFieldTemplates; +        if (typeof templates === 'string') { return templates; } + +        return await this._getDefaultTemplatesPromise(); +    } + +    _getDefaultTemplatesPromise() { +        if (this._defaultAnkiFieldTemplatesPromise === null) { +            this._defaultAnkiFieldTemplatesPromise = this._getDefaultTemplates(); +            this._defaultAnkiFieldTemplatesPromise.then( +                () => { this._defaultAnkiFieldTemplatesPromise = null; }, +                () => {} // NOP +            ); +        } +        return this._defaultAnkiFieldTemplatesPromise; +    } + +    async _getDefaultTemplates() { +        const value = await api.getDefaultAnkiFieldTemplates(); +        this._defaultAnkiFieldTemplates = value; +        return value; +    } + +    async _renderTemplate(template, data, marker) { +        return await this._templateRenderer.render(template, data, marker); +    } + +    async _addDefinition(definition, mode, context) { +        const options = this._options; +        const templates = await this._getTemplates(options); +        const note = await this._createNote(definition, mode, context, options, templates, true); +        return await api.addAnkiNote(note); +    } + +    async _areDefinitionsAddable(definitions, modes, context) { +        const options = this._options; +        const templates = await this._getTemplates(options); + +        const modeCount = modes.length; +        const {duplicateScope} = options.anki; +        const notePromises = []; +        for (const definition of definitions) { +            for (const mode of modes) { +                const notePromise = this._createNote(definition, mode, context, options, templates, false); +                notePromises.push(notePromise); +            } +        } +        const notes = await Promise.all(notePromises); + +        const infos = await api.getAnkiNoteInfo(notes, duplicateScope); +        const results = []; +        for (let i = 0, ii = infos.length; i < ii; i += modeCount) { +            results.push(infos.slice(i, i + modeCount)); +        } +        return results; +    } + +    async _createNote(definition, mode, context, options, templates, injectMedia) { +        const { +            general: {resultOutputMode, compactGlossaries}, +            anki: {tags, duplicateScope, kanji, terms, screenshot: {format, quality}}, +            audio: {sources, customSourceUrl} +        } = options; +        const modeOptions = (mode === 'kanji') ? kanji : terms; + +        if (injectMedia) { +            const timestamp = Date.now(); +            const ownerFrameId = this._ownerFrameId; +            const {fields} = modeOptions; +            const definitionExpressions = definition.expressions; +            const {expression, reading} = Array.isArray(definitionExpressions) ? definitionExpressions[0] : definition; +            const audioDetails = (mode !== 'kanji' && this._ankiNoteBuilder.containsMarker(fields, 'audio') ? {sources, customSourceUrl} : null); +            const screenshotDetails = (this._ankiNoteBuilder.containsMarker(fields, 'screenshot') ? {ownerFrameId, format, quality} : null); +            const clipboardImage = (this._ankiNoteBuilder.containsMarker(fields, 'clipboard-image')); +            const {screenshotFileName, clipboardImageFileName, audioFileName} = await api.injectAnkiNoteMedia( +                expression, +                reading, +                timestamp, +                audioDetails, +                screenshotDetails, +                clipboardImage +            ); +            if (screenshotFileName !== null) { definition.screenshotFileName = screenshotFileName; } +            if (clipboardImageFileName !== null) { definition.clipboardImageFileName = clipboardImageFileName; } +            if (audioFileName !== null) { definition.audioFileName = audioFileName; } +        } + +        return await this._ankiNoteBuilder.createNote({ +            definition, +            mode, +            context, +            templates, +            tags, +            duplicateScope, +            resultOutputMode, +            compactGlossaries, +            modeOptions +        }); +    }  } |