Anki note api functions (#802)

* Assign duplicateScope to a variable

* Add api.addAnkiNote

* Add api.getAnkiNoteInfo, update returned data format
This commit is contained in:
toasted-nutbread 2020-09-10 16:05:17 -04:00 committed by GitHub
parent 3dd4822ab3
commit 892f7ed3b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 48 deletions

View File

@ -91,6 +91,8 @@ class Backend {
['kanjiFind', {async: true, contentScript: true, handler: this._onApiKanjiFind.bind(this)}], ['kanjiFind', {async: true, contentScript: true, handler: this._onApiKanjiFind.bind(this)}],
['termsFind', {async: true, contentScript: true, handler: this._onApiTermsFind.bind(this)}], ['termsFind', {async: true, contentScript: true, handler: this._onApiTermsFind.bind(this)}],
['textParse', {async: true, contentScript: true, handler: this._onApiTextParse.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)}], ['definitionAdd', {async: true, contentScript: true, handler: this._onApiDefinitionAdd.bind(this)}],
['definitionsAddable', {async: true, contentScript: true, handler: this._onApiDefinitionsAddable.bind(this)}], ['definitionsAddable', {async: true, contentScript: true, handler: this._onApiDefinitionsAddable.bind(this)}],
['noteView', {async: true, contentScript: true, handler: this._onApiNoteView.bind(this)}], ['noteView', {async: true, contentScript: true, handler: this._onApiNoteView.bind(this)}],
@ -437,20 +439,53 @@ class Backend {
return results; 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) { async _onApiDefinitionAdd({definition, mode, context, ownerFrameId, optionsContext}, sender) {
const options = this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const templates = this._getTemplates(options); const templates = this._getTemplates(options);
const {id: tabId, windowId} = (sender && sender.tab ? sender.tab : {}); const {id: tabId, windowId} = (sender && sender.tab ? sender.tab : {});
const note = await this._createNote(definition, mode, context, options, templates, true, {windowId, tabId, ownerFrameId}); 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}) { async _onApiDefinitionsAddable({definitions, modes, context, optionsContext}) {
const options = this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const templates = this._getTemplates(options); const templates = this._getTemplates(options);
const states = [];
try { const modeCount = modes.length;
const {duplicateScope} = options.anki;
const notePromises = []; const notePromises = [];
for (const definition of definitions) { for (const definition of definitions) {
for (const mode of modes) { for (const mode of modes) {
@ -460,37 +495,12 @@ class Backend {
} }
const notes = await Promise.all(notePromises); const notes = await Promise.all(notePromises);
const cannotAdd = []; const infos = await this._onApiGetAnkiNoteInfo({notes, duplicateScope});
const results = await this._anki.canAddNotes(notes); const results = [];
for (let resultBase = 0; resultBase < results.length; resultBase += modes.length) { for (let i = 0, ii = infos.length; i < ii; i += modeCount) {
const state = {}; results.push(infos.slice(i, i + modeCount));
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]);
} }
} return results;
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
}
return states;
} }
async _onApiNoteView({noteId}) { async _onApiNoteView({noteId}) {

View File

@ -77,6 +77,14 @@ const api = (() => {
return this._invoke('kanjiFind', {text, optionsContext}); 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) { definitionAdd(definition, mode, context, ownerFrameId, optionsContext) {
return this._invoke('definitionAdd', {definition, mode, context, ownerFrameId, optionsContext}); return this._invoke('definitionAdd', {definition, mode, context, ownerFrameId, optionsContext});
} }

View File

@ -889,10 +889,15 @@ class Display extends EventDispatcher {
async _setContentTermsOrKanjiUpdateAdderButtons(token, isTerms, definitions) { async _setContentTermsOrKanjiUpdateAdderButtons(token, isTerms, definitions) {
const modes = isTerms ? ['term-kanji', 'term-kana'] : ['kanji']; 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; } if (this._setContentToken !== token) { return; }
this._updateAdderButtons(states); this._updateAdderButtons(states, modes);
} }
_setContentExtensionUnloaded() { _setContentExtensionUnloaded() {
@ -953,19 +958,22 @@ class Display extends EventDispatcher {
this._navigationHeader.dataset.hasNext = `${!!next}`; this._navigationHeader.dataset.hasNext = `${!!next}`;
} }
_updateAdderButtons(states) { _updateAdderButtons(states, modes) {
for (let i = 0; i < states.length; ++i) { for (let i = 0, ii = states.length; i < ii; ++i) {
const infos = states[i];
let noteId = null; 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); const button = this._adderButtonFind(i, mode);
if (button === null) { if (button === null) {
continue; continue;
} }
if (!info.canAdd && noteId === null && info.noteId) { if (Array.isArray(noteIds) && noteIds.length > 0) {
noteId = info.noteId; noteId = noteIds[0];
} }
button.classList.toggle('disabled', !info.canAdd); button.classList.toggle('disabled', !canAdd);
button.classList.remove('pending'); button.classList.remove('pending');
} }
if (noteId !== null) { if (noteId !== null) {