diff options
Diffstat (limited to 'ext/js/display/sandbox')
-rw-r--r-- | ext/js/display/sandbox/pronunciation-generator.js | 56 | ||||
-rw-r--r-- | ext/js/display/sandbox/structured-content-generator.js | 101 |
2 files changed, 143 insertions, 14 deletions
diff --git a/ext/js/display/sandbox/pronunciation-generator.js b/ext/js/display/sandbox/pronunciation-generator.js index 76d5e2b1..eeedc574 100644 --- a/ext/js/display/sandbox/pronunciation-generator.js +++ b/ext/js/display/sandbox/pronunciation-generator.js @@ -17,10 +17,21 @@ */ export class PronunciationGenerator { + /** + * @param {JapaneseUtil} japaneseUtil + */ constructor(japaneseUtil) { + /** @type {JapaneseUtil} */ this._japaneseUtil = japaneseUtil; } + /** + * @param {string[]} morae + * @param {number} downstepPosition + * @param {number[]} nasalPositions + * @param {number[]} devoicePositions + * @returns {HTMLSpanElement} + */ createPronunciationText(morae, downstepPosition, nasalPositions, devoicePositions) { const jp = this._japaneseUtil; const nasalPositionsSet = nasalPositions.length > 0 ? new Set(nasalPositions) : null; @@ -63,7 +74,7 @@ export class PronunciationGenerator { group.className = 'pronunciation-character-group'; const n2 = characterNodes[0]; - const character = n2.textContent; + const character = /** @type {string} */ (n2.textContent); const characterInfo = jp.getKanaDiacriticInfo(character); if (characterInfo !== null) { @@ -81,7 +92,7 @@ export class PronunciationGenerator { n3.className = 'pronunciation-nasal-indicator'; group.appendChild(n3); - n2.parentNode.replaceChild(group, n2); + /** @type {ParentNode} */ (n2.parentNode).replaceChild(group, n2); group.insertBefore(n2, group.firstChild); } @@ -94,6 +105,11 @@ export class PronunciationGenerator { return container; } + /** + * @param {string[]} morae + * @param {number} downstepPosition + * @returns {SVGSVGElement} + */ createPronunciationGraph(morae, downstepPosition) { const jp = this._japaneseUtil; const ii = morae.length; @@ -145,12 +161,16 @@ export class PronunciationGenerator { return svg; } + /** + * @param {number} downstepPosition + * @returns {HTMLSpanElement} + */ createPronunciationDownstepPosition(downstepPosition) { - downstepPosition = `${downstepPosition}`; + const downstepPositionString = `${downstepPosition}`; const n1 = document.createElement('span'); n1.className = 'pronunciation-downstep-notation'; - n1.dataset.downstepPosition = downstepPosition; + n1.dataset.downstepPosition = downstepPositionString; let n2 = document.createElement('span'); n2.className = 'pronunciation-downstep-notation-prefix'; @@ -159,7 +179,7 @@ export class PronunciationGenerator { n2 = document.createElement('span'); n2.className = 'pronunciation-downstep-notation-number'; - n2.textContent = downstepPosition; + n2.textContent = downstepPositionString; n1.appendChild(n2); n2 = document.createElement('span'); @@ -172,15 +192,33 @@ export class PronunciationGenerator { // Private + /** + * @param {Element} container + * @param {string} svgns + * @param {number} x + * @param {number} y + */ _addGraphDot(container, svgns, x, y) { container.appendChild(this._createGraphCircle(svgns, 'pronunciation-graph-dot', x, y, '15')); } + /** + * @param {Element} container + * @param {string} svgns + * @param {number} x + * @param {number} y + */ _addGraphDotDownstep(container, svgns, x, y) { container.appendChild(this._createGraphCircle(svgns, 'pronunciation-graph-dot-downstep1', x, y, '15')); container.appendChild(this._createGraphCircle(svgns, 'pronunciation-graph-dot-downstep2', x, y, '5')); } + /** + * @param {Element} container + * @param {string} svgns + * @param {number} x + * @param {number} y + */ _addGraphTriangle(container, svgns, x, y) { const node = document.createElementNS(svgns, 'path'); node.setAttribute('class', 'pronunciation-graph-triangle'); @@ -189,6 +227,14 @@ export class PronunciationGenerator { container.appendChild(node); } + /** + * @param {string} svgns + * @param {string} className + * @param {number} x + * @param {number} y + * @param {string} radius + * @returns {Element} + */ _createGraphCircle(svgns, className, x, y, radius) { const node = document.createElementNS(svgns, 'circle'); node.setAttribute('class', className); diff --git a/ext/js/display/sandbox/structured-content-generator.js b/ext/js/display/sandbox/structured-content-generator.js index 227892d6..af49b643 100644 --- a/ext/js/display/sandbox/structured-content-generator.js +++ b/ext/js/display/sandbox/structured-content-generator.js @@ -17,28 +17,51 @@ */ export class StructuredContentGenerator { + /** + * @param {DisplayContentManager|AnkiTemplateRendererContentManager} contentManager + * @param {JapaneseUtil} japaneseUtil + * @param {Document} document + */ constructor(contentManager, japaneseUtil, document) { + /** @type {DisplayContentManager|AnkiTemplateRendererContentManager} */ this._contentManager = contentManager; + /** @type {JapaneseUtil} */ this._japaneseUtil = japaneseUtil; + /** @type {Document} */ this._document = document; } + /** + * @param {HTMLElement} node + * @param {import('structured-content').Content} content + * @param {string} dictionary + */ appendStructuredContent(node, content, dictionary) { node.classList.add('structured-content'); this._appendStructuredContent(node, content, dictionary, null); } + /** + * @param {import('structured-content').Content} content + * @param {string} dictionary + * @returns {HTMLElement} + */ createStructuredContent(content, dictionary) { const node = this._createElement('span', 'structured-content'); this._appendStructuredContent(node, content, dictionary, null); return node; } + /** + * @param {import('structured-content').ImageElementBase} data + * @param {string} dictionary + * @returns {HTMLAnchorElement} + */ createDefinitionImage(data, dictionary) { const { path, - width, - height, + width = 100, + height = 100, preferredWidth, preferredHeight, title, @@ -65,7 +88,7 @@ export class StructuredContentGenerator { (hasPreferredHeight ? preferredHeight / invAspectRatio : width) ); - const node = this._createElement('a', 'gloss-image-link'); + const node = /** @type {HTMLAnchorElement} */ (this._createElement('a', 'gloss-image-link')); node.target = '_blank'; node.rel = 'noreferrer noopener'; @@ -78,7 +101,7 @@ export class StructuredContentGenerator { const imageBackground = this._createElement('span', 'gloss-image-background'); imageContainer.appendChild(imageBackground); - const image = this._createElement('img', 'gloss-image'); + const image = /** @type {HTMLImageElement} */ (this._createElement('img', 'gloss-image')); image.alt = ''; imageContainer.appendChild(image); @@ -126,6 +149,12 @@ export class StructuredContentGenerator { // Private + /** + * @param {HTMLElement} container + * @param {import('structured-content').Content|undefined} content + * @param {string} dictionary + * @param {?string} language + */ _appendStructuredContent(container, content, dictionary, language) { if (typeof content === 'string') { if (content.length > 0) { @@ -151,16 +180,29 @@ export class StructuredContentGenerator { } } + /** + * @param {string} tagName + * @param {string} className + * @returns {HTMLElement} + */ _createElement(tagName, className) { const node = this._document.createElement(tagName); node.className = className; return node; } + /** + * @param {string} data + * @returns {Text} + */ _createTextNode(data) { return this._document.createTextNode(data); } + /** + * @param {HTMLElement} element + * @param {import('structured-content').Data} data + */ _setElementDataset(element, data) { for (let [key, value] of Object.entries(data)) { if (key.length > 0) { @@ -175,6 +217,13 @@ export class StructuredContentGenerator { } } + /** + * @param {HTMLAnchorElement} node + * @param {HTMLImageElement} image + * @param {HTMLElement} imageBackground + * @param {?string} url + * @param {boolean} unloaded + */ _setImageData(node, image, imageBackground, url, unloaded) { if (url !== null) { image.src = url; @@ -189,6 +238,12 @@ export class StructuredContentGenerator { } } + /** + * @param {import('structured-content').Element} content + * @param {string} dictionary + * @param {?string} language + * @returns {?HTMLElement} + */ _createStructuredContentGenericElement(content, dictionary, language) { const {tag} = content; switch (tag) { @@ -222,6 +277,13 @@ export class StructuredContentGenerator { return null; } + /** + * @param {string} tag + * @param {import('structured-content').UnstyledElement} content + * @param {string} dictionary + * @param {?string} language + * @returns {HTMLElement} + */ _createStructuredContentTableElement(tag, content, dictionary, language) { const container = this._createElement('div', 'gloss-sc-table-container'); const table = this._createStructuredContentElement(tag, content, dictionary, language, 'table', true, false); @@ -229,6 +291,16 @@ export class StructuredContentGenerator { return container; } + /** + * @param {string} tag + * @param {import('structured-content').StyledElement|import('structured-content').UnstyledElement|import('structured-content').TableElement|import('structured-content').LineBreak} content + * @param {string} dictionary + * @param {?string} language + * @param {'simple'|'table'|'table-cell'} type + * @param {boolean} hasChildren + * @param {boolean} hasStyle + * @returns {HTMLElement} + */ _createStructuredContentElement(tag, content, dictionary, language, type, hasChildren, hasStyle) { const node = this._createElement(tag, `gloss-sc-${tag}`); const {data, lang} = content; @@ -240,14 +312,15 @@ export class StructuredContentGenerator { switch (type) { case 'table-cell': { - const {colSpan, rowSpan} = content; - if (typeof colSpan === 'number') { node.colSpan = colSpan; } - if (typeof rowSpan === 'number') { node.rowSpan = rowSpan; } + const cell = /** @type {HTMLTableCellElement} */ (node); + const {colSpan, rowSpan} = /** @type {import('structured-content').TableElement} */ (content); + if (typeof colSpan === 'number') { cell.colSpan = colSpan; } + if (typeof rowSpan === 'number') { cell.rowSpan = rowSpan; } } break; } if (hasStyle) { - const {style} = content; + const {style} = /** @type {import('structured-content').StyledElement} */ (content); if (typeof style === 'object' && style !== null) { this._setStructuredContentElementStyle(node, style); } @@ -258,6 +331,10 @@ export class StructuredContentGenerator { return node; } + /** + * @param {HTMLElement} node + * @param {import('structured-content').StructuredContentStyle} contentStyle + */ _setStructuredContentElementStyle(node, contentStyle) { const {style} = node; const { @@ -290,6 +367,12 @@ export class StructuredContentGenerator { if (typeof listStyleType === 'string') { style.listStyleType = listStyleType; } } + /** + * @param {import('structured-content').LinkElement} content + * @param {string} dictionary + * @param {?string} language + * @returns {HTMLAnchorElement} + */ _createLinkElement(content, dictionary, language) { let {href} = content; const internal = href.startsWith('?'); @@ -297,7 +380,7 @@ export class StructuredContentGenerator { href = `${location.protocol}//${location.host}/search.html${href.length > 1 ? href : ''}`; } - const node = this._createElement('a', 'gloss-link'); + const node = /** @type {HTMLAnchorElement} */ (this._createElement('a', 'gloss-link')); node.dataset.external = `${!internal}`; const text = this._createElement('span', 'gloss-link-text'); |