summaryrefslogtreecommitdiff
path: root/ext/mixed/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2021-01-30 12:33:29 -0500
committerGitHub <noreply@github.com>2021-01-30 12:33:29 -0500
commitd0b8b605db93c51b5ce2501a482c57432b45bfa6 (patch)
treec42bf4f59d7945c8b9c42cd0677e3827d326a71a /ext/mixed/js
parentaf6e9a8153c24d0400592005b31d56fecff67068 (diff)
Add note errors (#1329)
* Update _addAnkiNote to track errors * Change comparison * Update anki note adding to show errors * Fix template * Show errors when Anki card creation behaves unexpectedly * Update some errors related to anki media injection * Update addAnkiNote error handling * Improve Anki errors * Simplify error messages related to template rendering
Diffstat (limited to 'ext/mixed/js')
-rw-r--r--ext/mixed/js/display-generator.js17
-rw-r--r--ext/mixed/js/display.js106
2 files changed, 100 insertions, 23 deletions
diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js
index d7cc5bd4..70cbcf13 100644
--- a/ext/mixed/js/display-generator.js
+++ b/ext/mixed/js/display-generator.js
@@ -192,6 +192,23 @@ class DisplayGenerator {
return node;
}
+ createAnkiNoteErrorsNotificationContent(errors) {
+ const content = this._templates.instantiate('footer-notification-anki-errors-content');
+
+ const header = content.querySelector('.anki-note-error-header');
+ header.textContent = (errors.length === 1 ? 'An error occurred:' : `${errors.length} errors occurred:`);
+
+ const list = content.querySelector('.anki-note-error-list');
+ for (const error of errors) {
+ const div = document.createElement('li');
+ div.className = 'anki-note-error-message';
+ div.textContent = isObject(error) && typeof error.message === 'string' ? error.message : `${error}`;
+ list.appendChild(div);
+ }
+
+ return content;
+ }
+
createProfileListItem() {
return this._templates.instantiate('profile-list-item');
}
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index 15724fe4..c1044872 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -110,8 +110,10 @@ class Display extends EventDispatcher {
this._frameResizeStartOffset = null;
this._frameResizeEventListeners = new EventListenerCollection();
this._tagNotification = null;
- this._tagNotificationContainer = document.querySelector('#content-footer');
+ this._footerNotificationContainer = document.querySelector('#content-footer');
this._displayAudio = new DisplayAudio(this);
+ this._ankiNoteNotification = null;
+ this._ankiNoteNotificationEventListeners = null;
this._hotkeyHandler.registerActions([
['close', () => { this._onHotkeyClose(); }],
@@ -525,6 +527,7 @@ class Display extends EventDispatcher {
this._mediaLoader.unloadAll();
this._displayAudio.cleanupEntries();
this._hideTagNotification(false);
+ this._hideAnkiNoteErrors(false);
this._definitions = [];
this._definitionNodes = [];
@@ -791,7 +794,7 @@ class Display extends EventDispatcher {
if (this._tagNotification === null) {
const node = this._displayGenerator.createEmptyFooterNotification();
node.classList.add('click-scannable');
- this._tagNotification = new DisplayNotification(this._tagNotificationContainer, node);
+ this._tagNotification = new DisplayNotification(this._footerNotificationContainer, node);
}
const content = this._displayGenerator.createTagFooterNotificationDetails(tagNode);
@@ -1170,38 +1173,85 @@ class Display extends EventDispatcher {
}
async _addAnkiNote(definitionIndex, mode) {
- if (definitionIndex < 0 || definitionIndex >= this._definitions.length) { return false; }
+ if (definitionIndex < 0 || definitionIndex >= this._definitions.length) { return; }
const definition = this._definitions[definitionIndex];
const button = this._adderButtonFind(definitionIndex, mode);
- if (button === null || button.disabled) { return false; }
+ if (button === null || button.disabled) { return; }
+ this._hideAnkiNoteErrors(true);
+
+ const errors = [];
const overrideToken = this._progressIndicatorVisible.setOverride(true);
try {
const {anki: {suspendNewCards}} = this._options;
const noteContext = this._getNoteContext();
- const note = await this._createNote(definition, mode, noteContext, true);
- const noteId = await api.addAnkiNote(note);
- if (noteId) {
- if (suspendNewCards) {
- try {
- await api.suspendAnkiCardsForNote(noteId);
- } catch (e) {
- // NOP
+ const note = await this._createNote(definition, mode, noteContext, true, errors);
+
+ let noteId = null;
+ let addNoteOkay = false;
+ try {
+ noteId = await api.addAnkiNote(note);
+ addNoteOkay = true;
+ } catch (e) {
+ errors.length = 0;
+ errors.push(e);
+ }
+
+ if (addNoteOkay) {
+ if (noteId === null) {
+ errors.push(new Error('Note could not be added'));
+ } else {
+ if (suspendNewCards) {
+ try {
+ await api.suspendAnkiCardsForNote(noteId);
+ } catch (e) {
+ errors.push(e);
+ }
}
+ button.disabled = true;
+ this._viewerButtonShow(definitionIndex, noteId);
}
- button.disabled = true;
- this._viewerButtonShow(definitionIndex, noteId);
- } else {
- throw new Error('Note could not be added');
}
} catch (e) {
- this.onError(e);
- return false;
+ errors.push(e);
} finally {
this._progressIndicatorVisible.clearOverride(overrideToken);
}
- return true;
+
+ if (errors.length > 0) {
+ this._showAnkiNoteErrors(errors);
+ } else {
+ this._hideAnkiNoteErrors(true);
+ }
+ }
+
+ _showAnkiNoteErrors(errors) {
+ if (this._ankiNoteNotificationEventListeners !== null) {
+ this._ankiNoteNotificationEventListeners.removeAllEventListeners();
+ }
+
+ if (this._ankiNoteNotification === null) {
+ const node = this._displayGenerator.createEmptyFooterNotification();
+ this._ankiNoteNotification = new DisplayNotification(this._footerNotificationContainer, node);
+ this._ankiNoteNotificationEventListeners = new EventListenerCollection();
+ }
+
+ const content = this._displayGenerator.createAnkiNoteErrorsNotificationContent(errors);
+ for (const node of content.querySelectorAll('.anki-note-error-log-link')) {
+ this._ankiNoteNotificationEventListeners.addEventListener(node, 'click', () => {
+ console.log({ankiNoteErrors: errors});
+ }, false);
+ }
+
+ this._ankiNoteNotification.setContent(content);
+ this._ankiNoteNotification.open();
+ }
+
+ _hideAnkiNoteErrors(animate) {
+ if (this._ankiNoteNotification === null) { return; }
+ this._ankiNoteNotification.close(animate);
+ this._ankiNoteNotificationEventListeners.removeAllEventListeners();
}
async _playAudioCurrent() {
@@ -1372,7 +1422,7 @@ class Display extends EventDispatcher {
const notePromises = [];
for (const definition of definitions) {
for (const mode of modes) {
- const notePromise = this._createNote(definition, mode, context, false);
+ const notePromise = this._createNote(definition, mode, context, false, null);
notePromises.push(notePromise);
}
}
@@ -1400,7 +1450,7 @@ class Display extends EventDispatcher {
return results;
}
- async _createNote(definition, mode, context, injectMedia) {
+ async _createNote(definition, mode, context, injectMedia, errors) {
const options = this._options;
const templates = this._ankiFieldTemplates;
const {
@@ -1412,7 +1462,16 @@ class Display extends EventDispatcher {
const {deck: deckName, model: modelName} = modeOptions;
const fields = Object.entries(modeOptions.fields);
- const injectedMedia = (injectMedia ? await this._injectAnkiNoteMedia(definition, mode, options, fields) : null);
+ let injectedMedia = null;
+ if (injectMedia) {
+ let errors2;
+ ({result: injectedMedia, errors: errors2} = await this._injectAnkiNoteMedia(definition, mode, options, fields));
+ if (Array.isArray(errors)) {
+ for (const error of errors2) {
+ errors.push(deserializeError(error));
+ }
+ }
+ }
return await this._ankiNoteBuilder.createNote({
definition,
@@ -1428,7 +1487,8 @@ class Display extends EventDispatcher {
resultOutputMode,
glossaryLayoutMode,
compactTags,
- injectedMedia
+ injectedMedia,
+ errors
});
}