From 327d7b1f26d8553809292e159b97d44bc77b7b8e Mon Sep 17 00:00:00 2001
From: toasted-nutbread
Date: Fri, 30 Oct 2020 17:41:52 -0400
Subject: [PATCH] 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 +++-
.../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.
-