Anki templates refactor (#970)
* Support menus with multiple sources * Update anki templates controller
This commit is contained in:
parent
cb76848df9
commit
327d7b1f26
@ -272,7 +272,7 @@ html:root:not([data-options-general-result-output-mode=merge]) #dictionary-main-
|
|||||||
|
|
||||||
#custom-popup-css,
|
#custom-popup-css,
|
||||||
#custom-popup-outer-css,
|
#custom-popup-outer-css,
|
||||||
#field-templates {
|
#anki-card-templates-textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 34px;
|
min-height: 34px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
@ -280,12 +280,10 @@ html:root:not([data-options-general-result-output-mode=merge]) #dictionary-main-
|
|||||||
resize: vertical;
|
resize: vertical;
|
||||||
font-family: 'Courier New', Courier, monospace;
|
font-family: 'Courier New', Courier, monospace;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
}
|
|
||||||
#field-templates {
|
|
||||||
height: 240px;
|
height: 240px;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
}
|
}
|
||||||
#field-templates-reset {
|
#anki-card-templates-reset-button {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
@ -214,14 +214,20 @@ class AnkiController {
|
|||||||
|
|
||||||
_setupFieldMenus() {
|
_setupFieldMenus() {
|
||||||
const fieldMenuTargets = [
|
const fieldMenuTargets = [
|
||||||
['terms', '#anki-card-terms-field-menu-template'],
|
[['terms'], '#anki-card-terms-field-menu-template'],
|
||||||
['kanji', '#anki-card-kanji-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);
|
const element = document.querySelector(selector);
|
||||||
if (element === null) { continue; }
|
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');
|
const container = element.content.querySelector('.popup-menu');
|
||||||
if (container === null) { return; }
|
if (container === null) { return; }
|
||||||
|
|
||||||
|
@ -30,6 +30,10 @@ class AnkiTemplatesController {
|
|||||||
this._cachedDefinitionValue = null;
|
this._cachedDefinitionValue = null;
|
||||||
this._cachedDefinitionText = null;
|
this._cachedDefinitionText = null;
|
||||||
this._defaultFieldTemplates = null;
|
this._defaultFieldTemplates = null;
|
||||||
|
this._fieldTemplatesTextarea = null;
|
||||||
|
this._compileResultInfo = null;
|
||||||
|
this._renderFieldInput = null;
|
||||||
|
this._renderResult = null;
|
||||||
this._fieldTemplateResetModal = null;
|
this._fieldTemplateResetModal = null;
|
||||||
this._templateRenderer = new TemplateRendererProxy();
|
this._templateRenderer = new TemplateRendererProxy();
|
||||||
}
|
}
|
||||||
@ -37,24 +41,38 @@ class AnkiTemplatesController {
|
|||||||
async prepare() {
|
async prepare() {
|
||||||
this._defaultFieldTemplates = await api.getDefaultAnkiFieldTemplates();
|
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([
|
const markers = new Set([
|
||||||
...this._ankiController.getFieldMarkers('terms'),
|
...this._ankiController.getFieldMarkers('terms'),
|
||||||
...this._ankiController.getFieldMarkers('kanji')
|
...this._ankiController.getFieldMarkers('kanji')
|
||||||
]);
|
]);
|
||||||
const fragment = this._ankiController.getFieldMarkersHtml(markers);
|
|
||||||
|
|
||||||
const list = document.querySelector('#field-templates-list');
|
if (fieldList !== null) {
|
||||||
list.appendChild(fragment);
|
const fragment = this._ankiController.getFieldMarkersHtml(markers);
|
||||||
for (const node of list.querySelectorAll('.marker-link')) {
|
fieldList.appendChild(fragment);
|
||||||
|
for (const node of fieldList.querySelectorAll('.marker-link')) {
|
||||||
node.addEventListener('click', this._onMarkerClicked.bind(this), false);
|
node.addEventListener('click', this._onMarkerClicked.bind(this), false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelector('#field-templates').addEventListener('change', this._onChanged.bind(this), false);
|
this._fieldTemplatesTextarea.addEventListener('change', this._onChanged.bind(this), false);
|
||||||
document.querySelector('#field-template-render').addEventListener('click', this._onRender.bind(this), false);
|
testRenderButton.addEventListener('click', this._onRender.bind(this), false);
|
||||||
document.querySelector('#field-templates-reset').addEventListener('click', this._onReset.bind(this), false);
|
resetButton.addEventListener('click', this._onReset.bind(this), false);
|
||||||
document.querySelector('#field-templates-reset-confirm').addEventListener('click', this._onResetConfirm.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));
|
this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this));
|
||||||
|
|
||||||
@ -67,7 +85,7 @@ class AnkiTemplatesController {
|
|||||||
_onOptionsChanged({options}) {
|
_onOptionsChanged({options}) {
|
||||||
let templates = options.anki.fieldTemplates;
|
let templates = options.anki.fieldTemplates;
|
||||||
if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; }
|
if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; }
|
||||||
document.querySelector('#field-templates').value = templates;
|
this._fieldTemplatesTextarea.value = templates;
|
||||||
|
|
||||||
this._onValidateCompile();
|
this._onValidateCompile();
|
||||||
}
|
}
|
||||||
@ -84,9 +102,8 @@ class AnkiTemplatesController {
|
|||||||
|
|
||||||
const value = this._defaultFieldTemplates;
|
const value = this._defaultFieldTemplates;
|
||||||
|
|
||||||
const element = document.querySelector('#field-templates');
|
this._fieldTemplatesTextarea.value = value;
|
||||||
element.value = value;
|
this._fieldTemplatesTextarea.dispatchEvent(new Event('change'));
|
||||||
element.dispatchEvent(new Event('change'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onChanged(e) {
|
async _onChanged(e) {
|
||||||
@ -105,24 +122,37 @@ class AnkiTemplatesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onValidateCompile() {
|
_onValidateCompile() {
|
||||||
const infoNode = document.querySelector('#field-template-compile-result');
|
this._validate(this._compileResultInfo, '{expression}', 'term-kanji', false, true);
|
||||||
this._validate(infoNode, '{expression}', 'term-kanji', false, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMarkerClicked(e) {
|
_onMarkerClicked(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.querySelector('#field-template-render-text').value = `{${e.target.textContent}}`;
|
this._renderFieldInput.value = `{${e.target.textContent}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRender(e) {
|
_onRender(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const field = document.querySelector('#field-template-render-text').value;
|
const field = this._renderFieldInput.value;
|
||||||
const infoNode = document.querySelector('#field-template-render-result');
|
const infoNode = this._renderResult;
|
||||||
infoNode.hidden = true;
|
infoNode.hidden = true;
|
||||||
this._validate(infoNode, field, 'term-kanji', true, false);
|
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) {
|
async _getDefinition(text, optionsContext) {
|
||||||
if (this._cachedDefinitionText !== text) {
|
if (this._cachedDefinitionText !== text) {
|
||||||
const {definitions} = await api.termsFind(text, {}, optionsContext);
|
const {definitions} = await api.termsFind(text, {}, optionsContext);
|
||||||
@ -135,7 +165,7 @@ class AnkiTemplatesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _validate(infoNode, field, mode, showSuccessResult, invalidateInput) {
|
async _validate(infoNode, field, mode, showSuccessResult, invalidateInput) {
|
||||||
const text = document.querySelector('#field-templates-preview-text').value || '';
|
const text = this._renderTextInput.value || '';
|
||||||
const exceptions = [];
|
const exceptions = [];
|
||||||
let result = `No definition found for ${text}`;
|
let result = `No definition found for ${text}`;
|
||||||
try {
|
try {
|
||||||
@ -179,8 +209,7 @@ class AnkiTemplatesController {
|
|||||||
infoNode.textContent = hasException ? exceptions.map((e) => `${e}`).join('\n') : (showSuccessResult ? result : '');
|
infoNode.textContent = hasException ? exceptions.map((e) => `${e}`).join('\n') : (showSuccessResult ? result : '');
|
||||||
infoNode.classList.toggle('text-danger', hasException);
|
infoNode.classList.toggle('text-danger', hasException);
|
||||||
if (invalidateInput) {
|
if (invalidateInput) {
|
||||||
const input = document.querySelector('#field-templates');
|
this._fieldTemplatesTextarea.classList.toggle('is-invalid', hasException);
|
||||||
input.classList.toggle('is-invalid', hasException);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,32 +1004,32 @@
|
|||||||
their Anki cards. If you encounter problems with your changes, you can always reset to the default template settings.
|
their Anki cards. If you encounter problems with your changes, you can always reset to the default template settings.
|
||||||
</p>
|
</p>
|
||||||
<div class="ignore-form-changes">
|
<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>
|
||||||
<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>
|
</div>
|
||||||
<p></p>
|
<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>
|
<p>Templates can be tested using the inputs below.</p>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<label for="field-templates-preview-text">Preview text</label>
|
<label for="anki-card-templates-test-text-input">Preview text</label>
|
||||||
<input type="text" id="field-templates-preview-text" class="form-control" value="読め" placeholder="Preview text">
|
<input type="text" id="anki-card-templates-test-text-input" class="form-control" value="読め" placeholder="Preview text">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<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">
|
||||||
<div class="input-group-btn">
|
<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>
|
</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">
|
<div class="input-group-btn">
|
||||||
<button class="btn btn-default dropdown-toggle" id="field-templates-dropdown" data-toggle="dropdown"><span class="caret"></span></button>
|
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
|
||||||
<ul class="dropdown-menu dropdown-menu-right" id="field-templates-list"></ul>
|
<ul class="dropdown-menu dropdown-menu-right" id="anki-card-templates-field-list"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1037,10 +1037,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p></p>
|
<p></p>
|
||||||
<pre id="field-template-render-result" hidden></pre>
|
<pre id="anki-card-templates-render-result" hidden></pre>
|
||||||
</div>
|
</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-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -1053,7 +1053,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user