Template handler update (#896)

* Rename TemplateHandler to HtmlTemplateCollection

* Rename _templateHandler to _templates

* Allow creation from both string and element

* Simplify setup of templates, don't throw errors on invalid ID
This commit is contained in:
toasted-nutbread 2020-10-07 20:47:44 -04:00 committed by GitHub
parent 2d765d2c4e
commit cb1902eadd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 48 deletions

View File

@ -16,24 +16,24 @@
*/ */
/* global /* global
* TemplateHandler * HtmlTemplateCollection
* api * api
*/ */
class QueryParserGenerator { class QueryParserGenerator {
constructor() { constructor() {
this._templateHandler = null; this._templates = null;
} }
async prepare() { async prepare() {
const html = await api.getQueryParserTemplatesHtml(); const html = await api.getQueryParserTemplatesHtml();
this._templateHandler = new TemplateHandler(html); this._templates = new HtmlTemplateCollection(html);
} }
createParseResult(terms, preview=false) { createParseResult(terms, preview=false) {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
for (const term of terms) { for (const term of terms) {
const termContainer = this._templateHandler.instantiate(preview ? 'term-preview' : 'term'); const termContainer = this._templates.instantiate(preview ? 'term-preview' : 'term');
for (const segment of term) { for (const segment of term) {
if (!segment.text.trim()) { continue; } if (!segment.text.trim()) { continue; }
if (!segment.reading.trim()) { if (!segment.reading.trim()) {
@ -48,7 +48,7 @@ class QueryParserGenerator {
} }
createSegment(segment) { createSegment(segment) {
const segmentContainer = this._templateHandler.instantiate('segment'); const segmentContainer = this._templates.instantiate('segment');
const segmentTextContainer = segmentContainer.querySelector('.query-parser-segment-text'); const segmentTextContainer = segmentContainer.querySelector('.query-parser-segment-text');
const segmentReadingContainer = segmentContainer.querySelector('.query-parser-segment-reading'); const segmentReadingContainer = segmentContainer.querySelector('.query-parser-segment-reading');
segmentTextContainer.appendChild(this.createSegmentText(segment.text)); segmentTextContainer.appendChild(this.createSegmentText(segment.text));
@ -59,7 +59,7 @@ class QueryParserGenerator {
createSegmentText(text) { createSegmentText(text) {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
for (const chr of text) { for (const chr of text) {
const charContainer = this._templateHandler.instantiate('char'); const charContainer = this._templates.instantiate('char');
charContainer.textContent = chr; charContainer.textContent = chr;
fragment.appendChild(charContainer); fragment.appendChild(charContainer);
} }
@ -67,9 +67,9 @@ class QueryParserGenerator {
} }
createParserSelect(parseResults, selectedParser) { createParserSelect(parseResults, selectedParser) {
const selectContainer = this._templateHandler.instantiate('select'); const selectContainer = this._templates.instantiate('select');
for (const parseResult of parseResults) { for (const parseResult of parseResults) {
const optionContainer = this._templateHandler.instantiate('select-option'); const optionContainer = this._templates.instantiate('select-option');
optionContainer.value = parseResult.id; optionContainer.value = parseResult.id;
switch (parseResult.source) { switch (parseResult.source) {
case 'scanning-parser': case 'scanning-parser':

View File

@ -89,7 +89,7 @@
<script src="/mixed/js/media-loader.js"></script> <script src="/mixed/js/media-loader.js"></script>
<script src="/mixed/js/scroll.js"></script> <script src="/mixed/js/scroll.js"></script>
<script src="/mixed/js/text-scanner.js"></script> <script src="/mixed/js/text-scanner.js"></script>
<script src="/mixed/js/template-handler.js"></script> <script src="/mixed/js/html-template-collection.js"></script>
<script src="/mixed/js/text-to-speech-audio.js"></script> <script src="/mixed/js/text-to-speech-audio.js"></script>
<script src="/bg/js/anki-note-builder.js"></script> <script src="/bg/js/anki-note-builder.js"></script>

View File

@ -65,7 +65,7 @@
<script src="/mixed/js/media-loader.js"></script> <script src="/mixed/js/media-loader.js"></script>
<script src="/mixed/js/scroll.js"></script> <script src="/mixed/js/scroll.js"></script>
<script src="/mixed/js/text-scanner.js"></script> <script src="/mixed/js/text-scanner.js"></script>
<script src="/mixed/js/template-handler.js"></script> <script src="/mixed/js/html-template-collection.js"></script>
<script src="/mixed/js/text-to-speech-audio.js"></script> <script src="/mixed/js/text-to-speech-audio.js"></script>
<script src="/bg/js/anki-note-builder.js"></script> <script src="/bg/js/anki-note-builder.js"></script>

View File

@ -17,7 +17,7 @@
/* global /* global
* DictionaryDataUtil * DictionaryDataUtil
* TemplateHandler * HtmlTemplateCollection
* api * api
* jp * jp
*/ */
@ -25,17 +25,17 @@
class DisplayGenerator { class DisplayGenerator {
constructor({mediaLoader}) { constructor({mediaLoader}) {
this._mediaLoader = mediaLoader; this._mediaLoader = mediaLoader;
this._templateHandler = null; this._templates = null;
this._termPitchAccentStaticTemplateIsSetup = false; this._termPitchAccentStaticTemplateIsSetup = false;
} }
async prepare() { async prepare() {
const html = await api.getDisplayTemplatesHtml(); const html = await api.getDisplayTemplatesHtml();
this._templateHandler = new TemplateHandler(html); this._templates = new HtmlTemplateCollection(html);
} }
createTermEntry(details) { createTermEntry(details) {
const node = this._templateHandler.instantiate('term-entry'); const node = this._templates.instantiate('term-entry');
const expressionsContainer = node.querySelector('.term-expression-list'); const expressionsContainer = node.querySelector('.term-expression-list');
const reasonsContainer = node.querySelector('.term-reasons'); const reasonsContainer = node.querySelector('.term-reasons');
@ -83,7 +83,7 @@ class DisplayGenerator {
} }
createKanjiEntry(details) { createKanjiEntry(details) {
const node = this._templateHandler.instantiate('kanji-entry'); const node = this._templates.instantiate('kanji-entry');
const glyphContainer = node.querySelector('.kanji-glyph'); const glyphContainer = node.querySelector('.kanji-glyph');
const frequenciesContainer = node.querySelector('.frequencies'); const frequenciesContainer = node.querySelector('.frequencies');
@ -130,7 +130,7 @@ class DisplayGenerator {
// Private // Private
_createTermExpression(details, termTags) { _createTermExpression(details, termTags) {
const node = this._templateHandler.instantiate('term-expression'); const node = this._templates.instantiate('term-expression');
const expressionContainer = node.querySelector('.term-expression-text'); const expressionContainer = node.querySelector('.term-expression-text');
const tagContainer = node.querySelector('.tags'); const tagContainer = node.querySelector('.tags');
@ -164,7 +164,7 @@ class DisplayGenerator {
} }
_createTermReason(reason) { _createTermReason(reason) {
const fragment = this._templateHandler.instantiateFragment('term-reason'); const fragment = this._templates.instantiateFragment('term-reason');
const node = fragment.querySelector('.term-reason'); const node = fragment.querySelector('.term-reason');
node.textContent = reason; node.textContent = reason;
node.dataset.reason = reason; node.dataset.reason = reason;
@ -172,7 +172,7 @@ class DisplayGenerator {
} }
_createTermDefinitionItem(details) { _createTermDefinitionItem(details) {
const node = this._templateHandler.instantiate('term-definition-item'); const node = this._templates.instantiate('term-definition-item');
const tagListContainer = node.querySelector('.term-definition-tag-list'); const tagListContainer = node.querySelector('.term-definition-tag-list');
const onlyListContainer = node.querySelector('.term-definition-disambiguation-list'); const onlyListContainer = node.querySelector('.term-definition-disambiguation-list');
@ -202,7 +202,7 @@ class DisplayGenerator {
} }
_createTermGlossaryItemText(glossary) { _createTermGlossaryItemText(glossary) {
const node = this._templateHandler.instantiate('term-glossary-item'); const node = this._templates.instantiate('term-glossary-item');
const container = node.querySelector('.term-glossary'); const container = node.querySelector('.term-glossary');
if (container !== null) { if (container !== null) {
this._appendMultilineText(container, glossary); this._appendMultilineText(container, glossary);
@ -225,7 +225,7 @@ class DisplayGenerator {
width / height width / height
); );
const node = this._templateHandler.instantiate('term-glossary-item-image'); const node = this._templates.instantiate('term-glossary-item-image');
node.dataset.path = path; node.dataset.path = path;
node.dataset.dictionary = dictionary; node.dataset.dictionary = dictionary;
node.dataset.imageLoadState = 'not-loaded'; node.dataset.imageLoadState = 'not-loaded';
@ -273,7 +273,7 @@ class DisplayGenerator {
} }
_createTermDisambiguation(disambiguation) { _createTermDisambiguation(disambiguation) {
const node = this._templateHandler.instantiate('term-definition-disambiguation'); const node = this._templates.instantiate('term-definition-disambiguation');
node.dataset.term = disambiguation; node.dataset.term = disambiguation;
node.textContent = disambiguation; node.textContent = disambiguation;
return node; return node;
@ -287,7 +287,7 @@ class DisplayGenerator {
} }
_createKanjiGlossaryItem(glossary) { _createKanjiGlossaryItem(glossary) {
const node = this._templateHandler.instantiate('kanji-glossary-item'); const node = this._templates.instantiate('kanji-glossary-item');
const container = node.querySelector('.kanji-glossary'); const container = node.querySelector('.kanji-glossary');
if (container !== null) { if (container !== null) {
this._appendMultilineText(container, glossary); this._appendMultilineText(container, glossary);
@ -296,13 +296,13 @@ class DisplayGenerator {
} }
_createKanjiReading(reading) { _createKanjiReading(reading) {
const node = this._templateHandler.instantiate('kanji-reading'); const node = this._templates.instantiate('kanji-reading');
node.textContent = reading; node.textContent = reading;
return node; return node;
} }
_createKanjiInfoTable(details) { _createKanjiInfoTable(details) {
const node = this._templateHandler.instantiate('kanji-info-table'); const node = this._templates.instantiate('kanji-info-table');
const container = node.querySelector('.kanji-info-table-body'); const container = node.querySelector('.kanji-info-table-body');
@ -318,7 +318,7 @@ class DisplayGenerator {
} }
_createKanjiInfoTableItem(details) { _createKanjiInfoTableItem(details) {
const node = this._templateHandler.instantiate('kanji-info-table-item'); const node = this._templates.instantiate('kanji-info-table-item');
const nameNode = node.querySelector('.kanji-info-table-item-header'); const nameNode = node.querySelector('.kanji-info-table-item-header');
const valueNode = node.querySelector('.kanji-info-table-item-value'); const valueNode = node.querySelector('.kanji-info-table-item-value');
if (nameNode !== null) { if (nameNode !== null) {
@ -331,11 +331,11 @@ class DisplayGenerator {
} }
_createKanjiInfoTableItemEmpty() { _createKanjiInfoTableItemEmpty() {
return this._templateHandler.instantiate('kanji-info-table-empty'); return this._templates.instantiate('kanji-info-table-empty');
} }
_createTag(details) { _createTag(details) {
const node = this._templateHandler.instantiate('tag'); const node = this._templates.instantiate('tag');
const inner = node.querySelector('.tag-inner'); const inner = node.querySelector('.tag-inner');
@ -347,7 +347,7 @@ class DisplayGenerator {
} }
_createSearchTag(details) { _createSearchTag(details) {
const node = this._templateHandler.instantiate('tag-search'); const node = this._templates.instantiate('tag-search');
node.textContent = details.query; node.textContent = details.query;
@ -359,13 +359,13 @@ class DisplayGenerator {
_createPitches(details) { _createPitches(details) {
if (!this._termPitchAccentStaticTemplateIsSetup) { if (!this._termPitchAccentStaticTemplateIsSetup) {
this._termPitchAccentStaticTemplateIsSetup = true; this._termPitchAccentStaticTemplateIsSetup = true;
const t = this._templateHandler.instantiate('term-pitch-accent-static'); const t = this._templates.instantiate('term-pitch-accent-static');
document.head.appendChild(t); document.head.appendChild(t);
} }
const {dictionary, pitches} = details; const {dictionary, pitches} = details;
const node = this._templateHandler.instantiate('term-pitch-accent-group'); const node = this._templates.instantiate('term-pitch-accent-group');
node.dataset.dictionary = dictionary; node.dataset.dictionary = dictionary;
node.dataset.pitchesMulti = 'true'; node.dataset.pitchesMulti = 'true';
node.dataset.pitchesCount = `${pitches.length}`; node.dataset.pitchesCount = `${pitches.length}`;
@ -383,7 +383,7 @@ class DisplayGenerator {
const {reading, position, tags, exclusiveExpressions, exclusiveReadings} = details; const {reading, position, tags, exclusiveExpressions, exclusiveReadings} = details;
const morae = jp.getKanaMorae(reading); const morae = jp.getKanaMorae(reading);
const node = this._templateHandler.instantiate('term-pitch-accent'); const node = this._templates.instantiate('term-pitch-accent');
node.dataset.pitchAccentPosition = `${position}`; node.dataset.pitchAccentPosition = `${position}`;
node.dataset.tagCount = `${tags.length}`; node.dataset.tagCount = `${tags.length}`;
@ -403,7 +403,7 @@ class DisplayGenerator {
const highPitch = jp.isMoraPitchHigh(i, position); const highPitch = jp.isMoraPitchHigh(i, position);
const highPitchNext = jp.isMoraPitchHigh(i + 1, position); const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
const n1 = this._templateHandler.instantiate('term-pitch-accent-character'); const n1 = this._templates.instantiate('term-pitch-accent-character');
const n2 = n1.querySelector('.term-pitch-accent-character-inner'); const n2 = n1.querySelector('.term-pitch-accent-character-inner');
n1.dataset.position = `${i}`; n1.dataset.position = `${i}`;
@ -424,14 +424,14 @@ class DisplayGenerator {
_createPitchAccentDisambiguations(container, exclusiveExpressions, exclusiveReadings) { _createPitchAccentDisambiguations(container, exclusiveExpressions, exclusiveReadings) {
const templateName = 'term-pitch-accent-disambiguation'; const templateName = 'term-pitch-accent-disambiguation';
for (const exclusiveExpression of exclusiveExpressions) { for (const exclusiveExpression of exclusiveExpressions) {
const node = this._templateHandler.instantiate(templateName); const node = this._templates.instantiate(templateName);
node.dataset.type = 'expression'; node.dataset.type = 'expression';
node.textContent = exclusiveExpression; node.textContent = exclusiveExpression;
container.appendChild(node); container.appendChild(node);
} }
for (const exclusiveReading of exclusiveReadings) { for (const exclusiveReading of exclusiveReadings) {
const node = this._templateHandler.instantiate(templateName); const node = this._templates.instantiate(templateName);
node.dataset.type = 'reading'; node.dataset.type = 'reading';
node.textContent = exclusiveReading; node.textContent = exclusiveReading;
container.appendChild(node); container.appendChild(node);
@ -483,7 +483,7 @@ class DisplayGenerator {
} }
_createFrequencyTag(details) { _createFrequencyTag(details) {
const node = this._templateHandler.instantiate('tag-frequency'); const node = this._templates.instantiate('tag-frequency');
let n = node.querySelector('.term-frequency-dictionary-name'); let n = node.querySelector('.term-frequency-dictionary-name');
if (n !== null) { if (n !== null) {

View File

@ -15,23 +15,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
class HtmlTemplateCollection {
class TemplateHandler { constructor(source) {
constructor(html) {
this._templates = new Map(); this._templates = new Map();
const doc = new DOMParser().parseFromString(html, 'text/html'); const sourceNode = (
for (const template of doc.querySelectorAll('template')) { typeof source === 'string' ?
this._setTemplate(template); new DOMParser().parseFromString(source, 'text/html') :
} source
} );
_setTemplate(template) { const pattern = /^([\w\W]+)-template$/;
const idMatch = template.id.match(/^([a-z-]+)-template$/); for (const template of sourceNode.querySelectorAll('template')) {
if (!idMatch) { const match = pattern.exec(template.id);
throw new Error(`Invalid template ID: ${template.id}`); if (match === null) { continue; }
this._templates.set(match[1], template);
} }
this._templates.set(idMatch[1], template);
} }
instantiate(name) { instantiate(name) {