diff options
Diffstat (limited to 'ext/js/display/display-generator.js')
-rw-r--r-- | ext/js/display/display-generator.js | 182 |
1 files changed, 5 insertions, 177 deletions
diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index 7de65f78..74b3fdca 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -18,6 +18,7 @@ /* global * DictionaryDataUtil * HtmlTemplateCollection + * StructuredContentGenerator */ class DisplayGenerator { @@ -26,12 +27,14 @@ class DisplayGenerator { this._mediaLoader = mediaLoader; this._hotkeyHelpController = hotkeyHelpController; this._templates = null; + this._structuredContentGenerator = null; this._termPitchAccentStaticTemplateIsSetup = false; } async prepare() { const html = await yomichan.api.getDisplayTemplatesHtml(); this._templates = new HtmlTemplateCollection(html); + this._structuredContentGenerator = new StructuredContentGenerator(this._templates, this._mediaLoader, document); this.updateHotkeys(); } @@ -316,7 +319,7 @@ class DisplayGenerator { const node = this._templates.instantiate('gloss-item'); const contentContainer = node.querySelector('.gloss-content'); - const image = this._createDefinitionImage(data, dictionary); + const image = this._structuredContentGenerator.createDefinitionImage(data, dictionary); contentContainer.appendChild(image); if (typeof description === 'string') { @@ -331,7 +334,7 @@ class DisplayGenerator { _createTermDefinitionEntryStructuredContent(content, dictionary) { const node = this._templates.instantiate('gloss-item'); - const child = this._createStructuredContent(content, dictionary); + const child = this._structuredContentGenerator.createStructuredContent(content, dictionary); if (child !== null) { const contentContainer = node.querySelector('.gloss-content'); contentContainer.appendChild(child); @@ -339,181 +342,6 @@ class DisplayGenerator { return node; } - _createDefinitionImage(data, dictionary) { - const { - path, - width, - height, - preferredWidth, - preferredHeight, - title, - pixelated, - imageRendering, - appearance, - background, - collapsed, - collapsible, - verticalAlign, - sizeUnits - } = data; - - const hasPreferredWidth = (typeof preferredWidth === 'number'); - const hasPreferredHeight = (typeof preferredHeight === 'number'); - const aspectRatio = ( - hasPreferredWidth && hasPreferredHeight ? - preferredWidth / preferredHeight : - width / height - ); - const usedWidth = ( - hasPreferredWidth ? - preferredWidth : - (hasPreferredHeight ? preferredHeight * aspectRatio : width) - ); - - const node = this._templates.instantiate('gloss-item-image'); - const imageContainer = node.querySelector('.gloss-image-container'); - const aspectRatioSizer = node.querySelector('.gloss-image-aspect-ratio-sizer'); - const image = node.querySelector('.gloss-image'); - const imageBackground = node.querySelector('.gloss-image-background'); - - node.dataset.path = path; - node.dataset.dictionary = dictionary; - node.dataset.imageLoadState = 'not-loaded'; - node.dataset.hasAspectRatio = 'true'; - node.dataset.imageRendering = typeof imageRendering === 'string' ? imageRendering : (pixelated ? 'pixelated' : 'auto'); - node.dataset.appearance = typeof appearance === 'string' ? appearance : 'auto'; - node.dataset.background = typeof background === 'boolean' ? `${background}` : 'true'; - node.dataset.collapsed = typeof collapsed === 'boolean' ? `${collapsed}` : 'false'; - node.dataset.collapsible = typeof collapsible === 'boolean' ? `${collapsible}` : 'true'; - if (typeof verticalAlign === 'string') { - node.dataset.verticalAlign = verticalAlign; - } - if (typeof sizeUnits === 'string' && (hasPreferredWidth || hasPreferredHeight)) { - node.dataset.sizeUnits = sizeUnits; - } - - imageContainer.style.width = `${usedWidth}em`; - if (typeof title === 'string') { - imageContainer.title = title; - } - - aspectRatioSizer.style.paddingTop = `${aspectRatio * 100.0}%`; - - if (this._mediaLoader !== null) { - this._mediaLoader.loadMedia( - path, - dictionary, - (url) => this._setImageData(node, image, imageBackground, url, false), - () => this._setImageData(node, image, imageBackground, null, true) - ); - } - - return node; - } - - _setImageData(node, image, imageBackground, url, unloaded) { - if (url !== null) { - image.src = url; - node.href = url; - node.dataset.imageLoadState = 'loaded'; - imageBackground.style.setProperty('--image', `url("${url}")`); - } else { - image.removeAttribute('src'); - node.removeAttribute('href'); - node.dataset.imageLoadState = unloaded ? 'unloaded' : 'load-error'; - imageBackground.style.removeProperty('--image'); - } - } - - _createStructuredContent(content, dictionary) { - if (typeof content === 'string') { - return document.createTextNode(content); - } - if (!(typeof content === 'object' && content !== null)) { - return null; - } - if (Array.isArray(content)) { - const fragment = document.createDocumentFragment(); - for (const item of content) { - const child = this._createStructuredContent(item, dictionary); - if (child !== null) { fragment.appendChild(child); } - } - return fragment; - } - const {tag} = content; - switch (tag) { - case 'br': - return this._createStructuredContentElement(tag, content, dictionary, 'simple', false, false); - case 'ruby': - case 'rt': - case 'rp': - return this._createStructuredContentElement(tag, content, dictionary, 'simple', true, false); - case 'table': - return this._createStructuredContentTableElement(tag, content, dictionary); - case 'thead': - case 'tbody': - case 'tfoot': - case 'tr': - return this._createStructuredContentElement(tag, content, dictionary, 'table', true, false); - case 'th': - case 'td': - return this._createStructuredContentElement(tag, content, dictionary, 'table-cell', true, true); - case 'div': - case 'span': - return this._createStructuredContentElement(tag, content, dictionary, 'simple', true, true); - case 'img': - return this._createDefinitionImage(content, dictionary); - } - return null; - } - - _createStructuredContentTableElement(tag, content, dictionary) { - const container = document.createElement('div'); - container.classList = 'gloss-sc-table-container'; - const table = this._createStructuredContentElement(tag, content, dictionary, 'table', true, false); - container.appendChild(table); - return container; - } - - _createStructuredContentElement(tag, content, dictionary, type, hasChildren, hasStyle) { - const node = document.createElement(tag); - node.className = `gloss-sc-${tag}`; - switch (type) { - case 'table-cell': - { - const {colSpan, rowSpan} = content; - if (typeof colSpan === 'number') { node.colSpan = colSpan; } - if (typeof rowSpan === 'number') { node.rowSpan = rowSpan; } - } - break; - } - if (hasStyle) { - const {style} = content; - if (typeof style === 'object' && style !== null) { - this._setStructuredContentElementStyle(node, style); - } - } - if (hasChildren) { - const child = this._createStructuredContent(content.content, dictionary); - if (child !== null) { node.appendChild(child); } - } - return node; - } - - _setStructuredContentElementStyle(node, contentStyle) { - const {style} = node; - const {fontStyle, fontWeight, fontSize, textDecorationLine, verticalAlign} = contentStyle; - if (typeof fontStyle === 'string') { style.fontStyle = fontStyle; } - if (typeof fontWeight === 'string') { style.fontWeight = fontWeight; } - if (typeof fontSize === 'string') { style.fontSize = fontSize; } - if (typeof verticalAlign === 'string') { style.verticalAlign = verticalAlign; } - if (typeof textDecorationLine === 'string') { - style.textDecoration = textDecorationLine; - } else if (Array.isArray(textDecorationLine)) { - style.textDecoration = textDecorationLine.join(' '); - } - } - _createTermDisambiguation(disambiguation) { const node = this._templates.instantiate('definition-disambiguation'); node.dataset.term = disambiguation; |