diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2021-01-30 12:33:29 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-30 12:33:29 -0500 |
commit | d0b8b605db93c51b5ce2501a482c57432b45bfa6 (patch) | |
tree | c42bf4f59d7945c8b9c42cd0677e3827d326a71a /ext/mixed | |
parent | af6e9a8153c24d0400592005b31d56fecff67068 (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')
-rw-r--r-- | ext/mixed/css/display.css | 8 | ||||
-rw-r--r-- | ext/mixed/display-templates.html | 5 | ||||
-rw-r--r-- | ext/mixed/js/display-generator.js | 17 | ||||
-rw-r--r-- | ext/mixed/js/display.js | 106 |
4 files changed, 113 insertions, 23 deletions
diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 4a1e2324..e13d8f91 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -1675,6 +1675,14 @@ button.footer-notification-close-button:active { } +/* Anki errors */ +.anki-note-error-list { + margin: 0; + padding-left: 1.5em; + list-style: disc; +} + + /* Conditional styles */ :root:not([data-enable-search-tags=true]) .tag[data-category=search] { display: none; diff --git a/ext/mixed/display-templates.html b/ext/mixed/display-templates.html index 6b744271..0eb92282 100644 --- a/ext/mixed/display-templates.html +++ b/ext/mixed/display-templates.html @@ -145,6 +145,11 @@ <template id="footer-notification-tag-details-template" data-remove-whitespace-text="true"> <div class="tag-details"></div> <div class="tag-details-disambiguation-list"></div> +</template> +<template id="footer-notification-anki-errors-content-template" data-remove-whitespace-text="true"><div class="anki-note-error-info"> + <div class="anki-note-error-header"></div> + <ul class="anki-note-error-list"></ul> + <div class="anki-note-error-log-container"><a class="anki-note-error-log-link">Log debug info to console</a></div> </div></template> <template id="profile-list-item-template"><label class="profile-list-item"> <div class="profile-list-item-selection"><label class="radio"><input type="radio" class="profile-entry-is-default-radio" name="profile-entry-default-radio"><span class="radio-body"><span class="radio-border"></span><span class="radio-dot"></span></span></label></div> 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 }); } |