Anki templates refactor (#970)

* Support menus with multiple sources

* Update anki templates controller
This commit is contained in:
toasted-nutbread 2020-10-30 17:41:52 -04:00 committed by GitHub
parent cb76848df9
commit 327d7b1f26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 43 deletions

View File

@ -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;
}

View File

@ -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; }

View File

@ -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);
}
}

View File

@ -1004,32 +1004,32 @@
their Anki cards. If you encounter problems with your changes, you can always reset to the default template settings.
</p>
<div class="ignore-form-changes">
<textarea autocomplete="off" spellcheck="false" wrap="soft" class="form-control" rows="10" id="field-templates"></textarea>
<textarea autocomplete="off" spellcheck="false" wrap="soft" class="form-control" rows="10" id="anki-card-templates-textarea"></textarea>
</div>
<div>
<button class="btn btn-danger" id="field-templates-reset">Reset Templates</button>
<button class="btn btn-danger" id="anki-card-templates-reset-button">Reset Templates</button>
</div>
<p></p>
<pre id="field-template-compile-result" hidden></pre>
<pre id="anki-card-templates-compile-result" hidden></pre>
<p>Templates can be tested using the inputs below.</p>
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label for="field-templates-preview-text">Preview text</label>
<input type="text" id="field-templates-preview-text" class="form-control" value="読め" placeholder="Preview text">
<label for="anki-card-templates-test-text-input">Preview text</label>
<input type="text" id="anki-card-templates-test-text-input" class="form-control" value="読め" placeholder="Preview text">
</div>
<div class="col-xs-6">
<label for="field-template-render-text">Test field</label>
<label for="anki-card-templates-test-field-input">Test field</label>
<div class="input-group">
<div class="input-group-btn">
<button class="btn btn-default" id="field-template-render" title="Test"><span class="glyphicon glyphicon-play"></span></button>
<button class="btn btn-default" id="anki-card-templates-test-render-button" title="Test"><span class="glyphicon glyphicon-play"></span></button>
</div>
<input type="text" class="form-control" id="field-template-render-text" value="{expression}" placeholder="{marker}">
<input type="text" class="form-control" id="anki-card-templates-test-field-input" value="{expression}" placeholder="{marker}">
<div class="input-group-btn">
<button class="btn btn-default dropdown-toggle" id="field-templates-dropdown" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" id="field-templates-list"></ul>
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" id="anki-card-templates-field-list"></ul>
</div>
</div>
</div>
@ -1037,10 +1037,10 @@
</div>
<p></p>
<pre id="field-template-render-result" hidden></pre>
<pre id="anki-card-templates-render-result" hidden></pre>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="field-template-reset-modal">
<div class="modal fade" tabindex="-1" role="dialog" id="anki-card-templates-reset">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
@ -1053,7 +1053,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" id="field-templates-reset-confirm">Reset Templates</button>
<button type="button" class="btn btn-danger" id="anki-card-templates-reset-button-confirm">Reset Templates</button>
</div>
</div>
</div>