aboutsummaryrefslogtreecommitdiff
path: root/ext/js/background
diff options
context:
space:
mode:
authorEloy Robillard <eloy.robillard@gmail.com>2024-03-18 12:19:27 +0100
committerGitHub <noreply@github.com>2024-03-18 11:19:27 +0000
commit7ee76d708934adeef06479f7757beb22c6c01d14 (patch)
treec03ad4227e8a71939bb5efddffe57fa21a75b043 /ext/js/background
parent4fe881d68d4c1182bee2e78a559c2064aaf48b0d (diff)
Add an option to allow both viewing and adding duplicates (#693)
* Detect duplicates when checking if can add note * Display the stacked add buttons
Diffstat (limited to 'ext/js/background')
-rw-r--r--ext/js/background/backend.js87
1 files changed, 77 insertions, 10 deletions
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index 182f11aa..cd44a07f 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -544,22 +544,89 @@ export class Backend {
return await this._anki.addNote(note);
}
+ /**
+ * @param {import('anki').Note[]} notes
+ * @returns {Promise<({ canAdd: true; } | { canAdd: false; error: string; })[]>}
+ */
+ async detectDuplicateNotes(notes) {
+ // `allowDuplicate` is on for all notes by default, so we temporarily set it to false
+ // to check which notes are duplicates.
+ const notesNoDuplicatesAllowed = notes.map((note) => ({...note, options: {...note.options, allowDuplicate: false}}));
+
+ return await this._anki.canAddNotesWithErrorDetail(notesNoDuplicatesAllowed);
+ }
+
+ /**
+ * Partitions notes between those that can / cannot be added.
+ * It further sets the `isDuplicate` strings for notes that have a duplicate.
+ * @param {import('anki').Note[]} notes
+ * @returns {Promise<import('backend').CanAddResults>}
+ */
+ async partitionAddibleNotes(notes) {
+ const canAddResults = await this.detectDuplicateNotes(notes);
+
+ /** @type {{ note: import('anki').Note, isDuplicate: boolean }[]} */
+ const canAddArray = [];
+
+ /** @type {import('anki').Note[]} */
+ const cannotAddArray = [];
+
+ for (let i = 0; i < canAddResults.length; i++) {
+ const result = canAddResults[i];
+
+ // If the note is a duplicate, the error is "cannot create note because it is a duplicate".
+ if (result.canAdd) {
+ canAddArray.push({note: notes[i], isDuplicate: false});
+ } else if (result.error.endsWith('duplicate')) {
+ canAddArray.push({note: notes[i], isDuplicate: true});
+ } else {
+ cannotAddArray.push(notes[i]);
+ }
+ }
+
+ return {canAddArray, cannotAddArray};
+ }
+
/** @type {import('api').ApiHandler<'getAnkiNoteInfo'>} */
async _onApiGetAnkiNoteInfo({notes, fetchAdditionalInfo}) {
- /** @type {import('anki').NoteInfoWrapper[]} */
- const results = [];
+ const {canAddArray, cannotAddArray} = await this.partitionAddibleNotes(notes);
+
/** @type {{note: import('anki').Note, info: import('anki').NoteInfoWrapper}[]} */
- const cannotAdd = [];
- const canAddArray = await this._anki.canAddNotes(notes);
+ const cannotAdd = cannotAddArray.filter((note) => isNoteDataValid(note)).map((note) => ({note, info: {canAdd: false, valid: false, noteIds: null}}));
+
+ /** @type {import('anki').NoteInfoWrapper[]} */
+ const results = cannotAdd.map(({info}) => info);
+
+ /** @type {import('anki').Note[]} */
+ const duplicateNotes = [];
+
+ /** @type {number[]} */
+ const originalIndices = [];
+
+ for (let i = 0; i < canAddArray.length; i++) {
+ if (canAddArray[i].isDuplicate) {
+ duplicateNotes.push(canAddArray[i].note);
+ // Keep original indices to locate duplicate inside `duplicateNoteIds`
+ originalIndices.push(i);
+ }
+ }
+
+ const duplicateNoteIds = await this._anki.findNoteIds(duplicateNotes);
+
+ for (let i = 0; i < canAddArray.length; ++i) {
+ const {note, isDuplicate} = canAddArray[i];
- for (let i = 0; i < notes.length; ++i) {
- const note = notes[i];
- let canAdd = canAddArray[i];
const valid = isNoteDataValid(note);
- if (!valid) { canAdd = false; }
- const info = {canAdd, valid, noteIds: null};
+
+ const info = {
+ canAdd: valid,
+ valid,
+ noteIds: isDuplicate ? duplicateNoteIds[originalIndices.indexOf(i)] : null
+ };
+
results.push(info);
- if (!canAdd && valid) {
+
+ if (!valid) {
cannotAdd.push({note, info});
}
}