From 892f7ed3b8d4a97dd7fd8086a404c5e8ea1355fb Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Thu, 10 Sep 2020 16:05:17 -0400 Subject: [PATCH] Anki note api functions (#802) * Assign duplicateScope to a variable * Add api.addAnkiNote * Add api.getAnkiNoteInfo, update returned data format --- ext/bg/js/backend.js | 90 +++++++++++++++++++++++------------------ ext/mixed/js/api.js | 8 ++++ ext/mixed/js/display.js | 24 +++++++---- 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 47295a27..e3ef1e88 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -91,6 +91,8 @@ class Backend { ['kanjiFind', {async: true, contentScript: true, handler: this._onApiKanjiFind.bind(this)}], ['termsFind', {async: true, contentScript: true, handler: this._onApiTermsFind.bind(this)}], ['textParse', {async: true, contentScript: true, handler: this._onApiTextParse.bind(this)}], + ['addAnkiNote', {async: true, contentScript: true, handler: this._onApiAddAnkiNote.bind(this)}], + ['getAnkiNoteInfo', {async: true, contentScript: true, handler: this._onApiGetAnkiNoteInfo.bind(this)}], ['definitionAdd', {async: true, contentScript: true, handler: this._onApiDefinitionAdd.bind(this)}], ['definitionsAddable', {async: true, contentScript: true, handler: this._onApiDefinitionsAddable.bind(this)}], ['noteView', {async: true, contentScript: true, handler: this._onApiNoteView.bind(this)}], @@ -437,60 +439,68 @@ class Backend { return results; } + async _onApiAddAnkiNote({note}) { + return await this._anki.addNote(note); + } + + async _onApiGetAnkiNoteInfo({notes, duplicateScope}) { + const results = []; + const cannotAdd = []; + const canAddArray = await this._anki.canAddNotes(notes); + + for (let i = 0; i < notes.length; ++i) { + const note = notes[i]; + const canAdd = canAddArray[i]; + const info = {canAdd, noteIds: null}; + results.push(info); + if (!canAdd) { + cannotAdd.push({note, info}); + } + } + + if (cannotAdd.length > 0) { + const cannotAddNotes = cannotAdd.map(({note}) => note); + const noteIdsArray = await this._anki.findNoteIds(cannotAddNotes, duplicateScope); + for (let i = 0, ii = Math.min(cannotAdd.length, noteIdsArray.length); i < ii; ++i) { + const noteIds = noteIdsArray[i]; + if (noteIds.length > 0) { + cannotAdd[i].info.noteIds = noteIds; + } + } + } + + return results; + } + async _onApiDefinitionAdd({definition, mode, context, ownerFrameId, optionsContext}, sender) { const options = this.getOptions(optionsContext); const templates = this._getTemplates(options); const {id: tabId, windowId} = (sender && sender.tab ? sender.tab : {}); const note = await this._createNote(definition, mode, context, options, templates, true, {windowId, tabId, ownerFrameId}); - return this._anki.addNote(note); + return await this._onApiAddAnkiNote({note}); } async _onApiDefinitionsAddable({definitions, modes, context, optionsContext}) { const options = this.getOptions(optionsContext); const templates = this._getTemplates(options); - const states = []; - try { - const notePromises = []; - for (const definition of definitions) { - for (const mode of modes) { - const notePromise = this._createNote(definition, mode, context, options, templates, false, null); - notePromises.push(notePromise); - } + 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, null); + notePromises.push(notePromise); } - const notes = await Promise.all(notePromises); - - const cannotAdd = []; - const results = await this._anki.canAddNotes(notes); - for (let resultBase = 0; resultBase < results.length; resultBase += modes.length) { - const state = {}; - for (let modeOffset = 0; modeOffset < modes.length; ++modeOffset) { - const index = resultBase + modeOffset; - const result = results[index]; - const info = {canAdd: result}; - state[modes[modeOffset]] = info; - if (!result) { - cannotAdd.push([notes[index], info]); - } - } - - states.push(state); - } - - if (cannotAdd.length > 0) { - const noteIdsArray = await this._anki.findNoteIds(cannotAdd.map((e) => e[0]), options.anki.duplicateScope); - for (let i = 0, ii = Math.min(cannotAdd.length, noteIdsArray.length); i < ii; ++i) { - const noteIds = noteIdsArray[i]; - if (noteIds.length > 0) { - cannotAdd[i][1].noteId = noteIds[0]; - } - } - } - } catch (e) { - // NOP } + const notes = await Promise.all(notePromises); - return states; + const infos = await this._onApiGetAnkiNoteInfo({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 _onApiNoteView({noteId}) { diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index 7dc77fb6..d9569187 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -77,6 +77,14 @@ const api = (() => { return this._invoke('kanjiFind', {text, optionsContext}); } + addAnkiNote(note) { + return this._invoke('addAnkiNote', {note}); + } + + getAnkiNoteInfo(notes, duplicateScope) { + return this._invoke('getAnkiNoteInfo', {notes, duplicateScope}); + } + definitionAdd(definition, mode, context, ownerFrameId, optionsContext) { return this._invoke('definitionAdd', {definition, mode, context, ownerFrameId, optionsContext}); } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 6fdab46b..7dd5920a 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -889,10 +889,15 @@ class Display extends EventDispatcher { async _setContentTermsOrKanjiUpdateAdderButtons(token, isTerms, definitions) { const modes = isTerms ? ['term-kanji', 'term-kana'] : ['kanji']; - const states = await this._getDefinitionsAddable(definitions, modes); + let states; + try { + states = await this._getDefinitionsAddable(definitions, modes); + } catch (e) { + return; + } if (this._setContentToken !== token) { return; } - this._updateAdderButtons(states); + this._updateAdderButtons(states, modes); } _setContentExtensionUnloaded() { @@ -953,19 +958,22 @@ class Display extends EventDispatcher { this._navigationHeader.dataset.hasNext = `${!!next}`; } - _updateAdderButtons(states) { - for (let i = 0; i < states.length; ++i) { + _updateAdderButtons(states, modes) { + for (let i = 0, ii = states.length; i < ii; ++i) { + const infos = states[i]; let noteId = null; - for (const [mode, info] of Object.entries(states[i])) { + for (let j = 0, jj = infos.length; j < jj; ++j) { + const {canAdd, noteIds} = infos[j]; + const mode = modes[j]; const button = this._adderButtonFind(i, mode); if (button === null) { continue; } - if (!info.canAdd && noteId === null && info.noteId) { - noteId = info.noteId; + if (Array.isArray(noteIds) && noteIds.length > 0) { + noteId = noteIds[0]; } - button.classList.toggle('disabled', !info.canAdd); + button.classList.toggle('disabled', !canAdd); button.classList.remove('pending'); } if (noteId !== null) {