diff --git a/ext/bg/js/anki.js b/ext/bg/js/anki.js index ba5b4161..05c07ce2 100644 --- a/ext/bg/js/anki.js +++ b/ext/bg/js/anki.js @@ -103,12 +103,12 @@ class AnkiConnect { return await this._invoke('storeMediaFile', {filename: fileName, data: dataBase64}); } - async findNoteIds(notes, duplicateScope) { + async findNoteIds(notes) { if (!this._enabled) { return []; } await this._checkVersion(); const actions = notes.map((note) => { let query = ''; - switch (duplicateScope) { + switch (this._getDuplicateScopeFromNote(note)) { case 'deck': query = `"deck:${this._escapeQuery(note.deckName)}" `; break; @@ -178,4 +178,15 @@ class AnkiConnect { const key = fieldNames[0]; return `"${key.toLowerCase()}:${this._escapeQuery(fields[key])}"`; } + + _getDuplicateScopeFromNote(note) { + const {options} = note; + if (typeof options === 'object' && options !== null) { + const {duplicateScope} = options; + if (typeof duplicateScope !== 'undefined') { + return duplicateScope; + } + } + return null; + } } diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index db83d0b7..6410b0fc 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -447,7 +447,7 @@ class Backend { return await this._anki.addNote(note); } - async _onApiGetAnkiNoteInfo({notes, duplicateScope}) { + async _onApiGetAnkiNoteInfo({notes}) { const results = []; const cannotAdd = []; const canAddArray = await this._anki.canAddNotes(notes); @@ -464,7 +464,7 @@ class Backend { if (cannotAdd.length > 0) { const cannotAddNotes = cannotAdd.map(({note}) => note); - const noteIdsArray = await this._anki.findNoteIds(cannotAddNotes, duplicateScope); + const noteIdsArray = await this._anki.findNoteIds(cannotAddNotes); for (let i = 0, ii = Math.min(cannotAdd.length, noteIdsArray.length); i < ii; ++i) { const noteIds = noteIdsArray[i]; if (noteIds.length > 0) { diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index d7cf4ea2..4fde30b0 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -81,8 +81,8 @@ const api = (() => { return this._invoke('addAnkiNote', {note}); } - getAnkiNoteInfo(notes, duplicateScope) { - return this._invoke('getAnkiNoteInfo', {notes, duplicateScope}); + getAnkiNoteInfo(notes) { + return this._invoke('getAnkiNoteInfo', {notes}); } injectAnkiNoteMedia(timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails) { diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 3cb4b0e4..ea30030c 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -86,8 +86,8 @@ class Display extends EventDispatcher { documentUtil: this._documentUtil }); this._mode = null; - this._defaultAnkiFieldTemplates = null; - this._defaultAnkiFieldTemplatesPromise = null; + this._ankiFieldTemplates = null; + this._ankiFieldTemplatesDefault = null; this._ankiNoteBuilder = new AnkiNoteBuilder(true); this._updateAdderButtonsPromise = Promise.resolve(); this._contentScrollElement = document.querySelector('#content-scroll'); @@ -125,10 +125,10 @@ class Display extends EventDispatcher { ['firstEntry', () => { this._focusEntry(0, true); }], ['historyBackward', () => { this._sourceTermView(); }], ['historyForward', () => { this._nextTermView(); }], - ['addNoteKanji', () => { this._noteTryAdd('kanji'); }], - ['addNoteTermKanji', () => { this._noteTryAdd('term-kanji'); }], - ['addNoteTermKana', () => { this._noteTryAdd('term-kana'); }], - ['viewNote', () => { this._noteTryView(); }], + ['addNoteKanji', () => { this._tryAddAnkiNoteForSelectedDefinition('kanji'); }], + ['addNoteTermKanji', () => { this._tryAddAnkiNoteForSelectedDefinition('term-kanji'); }], + ['addNoteTermKana', () => { this._tryAddAnkiNoteForSelectedDefinition('term-kana'); }], + ['viewNote', () => { this._tryViewAnkiNoteForSelectedDefinition(); }], ['playAudio', () => { this._playAudioCurrent(); }], ['copyHostSelection', () => this._copyHostSelection()] ]); @@ -304,8 +304,10 @@ class Display extends EventDispatcher { async updateOptions() { const options = await api.optionsGet(this.getOptionsContext()); + const templates = await this._getAnkiFieldTemplates(options); const {scanning: scanningOptions, sentenceParsing: sentenceParsingOptions} = options; this._options = options; + this._ankiFieldTemplates = templates; this._updateDocumentOptions(options); this._updateTheme(options.general.popupTheme); @@ -747,9 +749,7 @@ class Display extends EventDispatcher { e.preventDefault(); const link = e.currentTarget; const index = this._getClosestDefinitionIndex(link); - if (index < 0 || index >= this._definitions.length) { return; } - - this._noteAdd(this._definitions[index], link.dataset.mode); + this._addAnkiNote(index, link.dataset.mode); } _onNoteView(e) { @@ -1188,43 +1188,42 @@ class Display extends EventDispatcher { } } - _noteTryAdd(mode) { - const index = this._index; - if (index < 0 || index >= this._definitions.length) { return; } - - const button = this._adderButtonFind(index, mode); - if (button !== null && !button.disabled) { - this._noteAdd(this._definitions[index], mode); - } + _tryAddAnkiNoteForSelectedDefinition(mode) { + this._addAnkiNote(this._index, mode); } - _noteTryView() { + _tryViewAnkiNoteForSelectedDefinition() { const button = this._viewerButtonFind(this._index); if (button !== null && !button.disabled) { api.noteView(button.dataset.noteId); } } - async _noteAdd(definition, mode) { + async _addAnkiNote(definitionIndex, mode) { + if (definitionIndex < 0 || definitionIndex >= this._definitions.length) { return false; } + const definition = this._definitions[definitionIndex]; + + const button = this._adderButtonFind(definitionIndex, mode); + if (button === null || button.disabled) { return false; } + const overrideToken = this._progressIndicatorVisible.setOverride(true); try { const noteContext = await this._getNoteContext(); - const noteId = await this._addDefinition(definition, mode, noteContext); + const note = await this._createNote(definition, mode, noteContext, true); + const noteId = await api.addAnkiNote(note); if (noteId) { - const index = this._definitions.indexOf(definition); - const adderButton = this._adderButtonFind(index, mode); - if (adderButton !== null) { - adderButton.disabled = true; - } - this._viewerButtonShow(index, noteId); + button.disabled = true; + this._viewerButtonShow(definitionIndex, noteId); } else { throw new Error('Note could not be added'); } } catch (e) { this.onError(e); + return false; } finally { this._progressIndicatorVisible.clearOverride(overrideToken); } + return true; } async _playAudio(definitionIndex, expressionIndex) { @@ -1462,56 +1461,30 @@ class Display extends EventDispatcher { this.trigger('modeChange', {mode}); } - async _getTemplates(options) { + async _getAnkiFieldTemplates(options) { let templates = options.anki.fieldTemplates; if (typeof templates === 'string') { return templates; } - templates = this._defaultAnkiFieldTemplates; + templates = this._ankiFieldTemplatesDefault; 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 _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); + templates = await api.getDefaultAnkiFieldTemplates(); + this._ankiFieldTemplatesDefault = templates; + return templates; } 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); + const notePromise = this._createNote(definition, mode, context, false); notePromises.push(notePromise); } } const notes = await Promise.all(notePromises); - const infos = await api.getAnkiNoteInfo(notes, duplicateScope); + const infos = await api.getAnkiNoteInfo(notes); const results = []; for (let i = 0, ii = infos.length; i < ii; i += modeCount) { results.push(infos.slice(i, i + modeCount)); @@ -1533,7 +1506,9 @@ class Display extends EventDispatcher { return results; } - async _createNote(definition, mode, context, options, templates, injectMedia) { + async _createNote(definition, mode, context, injectMedia) { + const options = this._options; + const templates = this._ankiFieldTemplates; const { general: {resultOutputMode, glossaryLayoutMode, compactTags}, anki: ankiOptions