From 327d7b1f26d8553809292e159b97d44bc77b7b8e Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Fri, 30 Oct 2020 17:41:52 -0400 Subject: Anki templates refactor (#970) * Support menus with multiple sources * Update anki templates controller --- ext/bg/css/settings.css | 6 +- ext/bg/js/settings/anki-controller.js | 14 +++-- ext/bg/js/settings/anki-templates-controller.js | 73 +++++++++++++++++-------- ext/bg/settings.html | 26 ++++----- 4 files changed, 76 insertions(+), 43 deletions(-) diff --git a/ext/bg/css/settings.css b/ext/bg/css/settings.css index 231df1b3..5416371f 100644 --- a/ext/bg/css/settings.css +++ b/ext/bg/css/settings.css @@ -272,7 +272,7 @@ html:root:not([data-options-general-result-output-mode=merge]) #dictionary-main- #custom-popup-css, #custom-popup-outer-css, -#field-templates { +#anki-card-templates-textarea { width: 100%; min-height: 34px; line-height: 18px; @@ -280,12 +280,10 @@ html:root:not([data-options-general-result-output-mode=merge]) #dictionary-main- resize: vertical; font-family: 'Courier New', Courier, monospace; white-space: pre; -} -#field-templates { height: 240px; border-bottom-left-radius: 0; } -#field-templates-reset { +#anki-card-templates-reset-button { border-top-left-radius: 0; border-top-right-radius: 0; } diff --git a/ext/bg/js/settings/anki-controller.js b/ext/bg/js/settings/anki-controller.js index 6988e4b8..c205c160 100644 --- a/ext/bg/js/settings/anki-controller.js +++ b/ext/bg/js/settings/anki-controller.js @@ -214,14 +214,20 @@ class AnkiController { _setupFieldMenus() { const fieldMenuTargets = [ - ['terms', '#anki-card-terms-field-menu-template'], - ['kanji', '#anki-card-kanji-field-menu-template'] + [['terms'], '#anki-card-terms-field-menu-template'], + [['kanji'], '#anki-card-kanji-field-menu-template'], + [['terms', 'kanji'], '#anki-card-all-field-menu-template'] ]; - for (const [type, selector] of fieldMenuTargets) { + for (const [types, selector] of fieldMenuTargets) { const element = document.querySelector(selector); if (element === null) { continue; } - const markers = this.getFieldMarkers(type); + let markers = []; + for (const type of types) { + markers.push(...this.getFieldMarkers(type)); + } + markers = [...new Set(markers)]; + const container = element.content.querySelector('.popup-menu'); if (container === null) { return; } diff --git a/ext/bg/js/settings/anki-templates-controller.js b/ext/bg/js/settings/anki-templates-controller.js index 65900336..e6bab256 100644 --- a/ext/bg/js/settings/anki-templates-controller.js +++ b/ext/bg/js/settings/anki-templates-controller.js @@ -30,6 +30,10 @@ class AnkiTemplatesController { this._cachedDefinitionValue = null; this._cachedDefinitionText = null; this._defaultFieldTemplates = null; + this._fieldTemplatesTextarea = null; + this._compileResultInfo = null; + this._renderFieldInput = null; + this._renderResult = null; this._fieldTemplateResetModal = null; this._templateRenderer = new TemplateRendererProxy(); } @@ -37,24 +41,38 @@ class AnkiTemplatesController { async prepare() { this._defaultFieldTemplates = await api.getDefaultAnkiFieldTemplates(); - this._fieldTemplateResetModal = this._modalController.getModal('field-template-reset-modal'); + this._fieldTemplatesTextarea = document.querySelector('#anki-card-templates-textarea'); + this._compileResultInfo = document.querySelector('#anki-card-templates-compile-result'); + this._renderFieldInput = document.querySelector('#anki-card-templates-test-field-input'); + this._renderTextInput = document.querySelector('#anki-card-templates-test-text-input'); + this._renderResult = document.querySelector('#anki-card-templates-render-result'); + const menuButton = document.querySelector('#anki-card-templates-test-field-menu-button'); + const testRenderButton = document.querySelector('#anki-card-templates-test-render-button'); + const resetButton = document.querySelector('#anki-card-templates-reset-button'); + const resetConfirmButton = document.querySelector('#anki-card-templates-reset-button-confirm'); + const fieldList = document.querySelector('#anki-card-templates-field-list'); + this._fieldTemplateResetModal = this._modalController.getModal('anki-card-templates-reset'); const markers = new Set([ ...this._ankiController.getFieldMarkers('terms'), ...this._ankiController.getFieldMarkers('kanji') ]); - const fragment = this._ankiController.getFieldMarkersHtml(markers); - const list = document.querySelector('#field-templates-list'); - list.appendChild(fragment); - for (const node of list.querySelectorAll('.marker-link')) { - node.addEventListener('click', this._onMarkerClicked.bind(this), false); + if (fieldList !== null) { + const fragment = this._ankiController.getFieldMarkersHtml(markers); + fieldList.appendChild(fragment); + for (const node of fieldList.querySelectorAll('.marker-link')) { + node.addEventListener('click', this._onMarkerClicked.bind(this), false); + } } - document.querySelector('#field-templates').addEventListener('change', this._onChanged.bind(this), false); - document.querySelector('#field-template-render').addEventListener('click', this._onRender.bind(this), false); - document.querySelector('#field-templates-reset').addEventListener('click', this._onReset.bind(this), false); - document.querySelector('#field-templates-reset-confirm').addEventListener('click', this._onResetConfirm.bind(this), false); + this._fieldTemplatesTextarea.addEventListener('change', this._onChanged.bind(this), false); + testRenderButton.addEventListener('click', this._onRender.bind(this), false); + resetButton.addEventListener('click', this._onReset.bind(this), false); + resetConfirmButton.addEventListener('click', this._onResetConfirm.bind(this), false); + if (menuButton !== null) { + menuButton.addEventListener('menuClosed', this._onFieldMenuClosed.bind(this), false); + } this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); @@ -67,7 +85,7 @@ class AnkiTemplatesController { _onOptionsChanged({options}) { let templates = options.anki.fieldTemplates; if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; } - document.querySelector('#field-templates').value = templates; + this._fieldTemplatesTextarea.value = templates; this._onValidateCompile(); } @@ -84,9 +102,8 @@ class AnkiTemplatesController { const value = this._defaultFieldTemplates; - const element = document.querySelector('#field-templates'); - element.value = value; - element.dispatchEvent(new Event('change')); + this._fieldTemplatesTextarea.value = value; + this._fieldTemplatesTextarea.dispatchEvent(new Event('change')); } async _onChanged(e) { @@ -105,24 +122,37 @@ class AnkiTemplatesController { } _onValidateCompile() { - const infoNode = document.querySelector('#field-template-compile-result'); - this._validate(infoNode, '{expression}', 'term-kanji', false, true); + this._validate(this._compileResultInfo, '{expression}', 'term-kanji', false, true); } _onMarkerClicked(e) { e.preventDefault(); - document.querySelector('#field-template-render-text').value = `{${e.target.textContent}}`; + this._renderFieldInput.value = `{${e.target.textContent}}`; } _onRender(e) { e.preventDefault(); - const field = document.querySelector('#field-template-render-text').value; - const infoNode = document.querySelector('#field-template-render-result'); + const field = this._renderFieldInput.value; + const infoNode = this._renderResult; infoNode.hidden = true; this._validate(infoNode, field, 'term-kanji', true, false); } + _onFieldMenuClosed({currentTarget: node, detail: {action, item}}) { + switch (action) { + case 'setFieldMarker': + this._setFieldMarker(node, item.dataset.marker); + break; + } + } + + _setFieldMarker(element, marker) { + const input = this._renderFieldInput; + input.value = `{${marker}}`; + input.dispatchEvent(new Event('change')); + } + async _getDefinition(text, optionsContext) { if (this._cachedDefinitionText !== text) { const {definitions} = await api.termsFind(text, {}, optionsContext); @@ -135,7 +165,7 @@ class AnkiTemplatesController { } async _validate(infoNode, field, mode, showSuccessResult, invalidateInput) { - const text = document.querySelector('#field-templates-preview-text').value || ''; + const text = this._renderTextInput.value || ''; const exceptions = []; let result = `No definition found for ${text}`; try { @@ -179,8 +209,7 @@ class AnkiTemplatesController { infoNode.textContent = hasException ? exceptions.map((e) => `${e}`).join('\n') : (showSuccessResult ? result : ''); infoNode.classList.toggle('text-danger', hasException); if (invalidateInput) { - const input = document.querySelector('#field-templates'); - input.classList.toggle('is-invalid', hasException); + this._fieldTemplatesTextarea.classList.toggle('is-invalid', hasException); } } diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 066662e5..1b1e9124 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -1004,32 +1004,32 @@ their Anki cards. If you encounter problems with your changes, you can always reset to the default template settings.

- +
- +

- +

Templates can be tested using the inputs below.

- - + +
- +
- +
- +
- - + +
@@ -1037,10 +1037,10 @@

- +
-