aboutsummaryrefslogtreecommitdiff
path: root/ext/js/display/sandbox
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js/display/sandbox')
-rw-r--r--ext/js/display/sandbox/pronunciation-generator.js56
-rw-r--r--ext/js/display/sandbox/structured-content-generator.js101
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..d113485f 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 {import('../../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil
+ */
constructor(japaneseUtil) {
+ /** @type {import('../../language/sandbox/japanese-util.js').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..5a91b01c 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 {import('../../display/display-content-manager.js').DisplayContentManager|import('../../templates/sandbox/anki-template-renderer-content-manager.js').AnkiTemplateRendererContentManager} contentManager
+ * @param {import('../../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil
+ * @param {Document} document
+ */
constructor(contentManager, japaneseUtil, document) {
+ /** @type {import('../../display/display-content-manager.js').DisplayContentManager|import('../../templates/sandbox/anki-template-renderer-content-manager.js').AnkiTemplateRendererContentManager} */
this._contentManager = contentManager;
+ /** @type {import('../../language/sandbox/japanese-util.js').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');