summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2021-07-18 13:43:11 -0400
committerGitHub <noreply@github.com>2021-07-18 13:43:11 -0400
commit637d4a2087b9e93ccd47d689411887b6c40c3992 (patch)
treef893a08502b79f8cc03b186394665dd721377bc4 /ext
parent10a9da4d31b4837d8c48e3cd1c36a7b760691d74 (diff)
Pronunciation template helper (#1840)
* Rename field * Set up pronunication components * Fix documentation * Rename function * Update test dependencies * Fix constructor * Log errors * Add pronunciation helper * Add styleApplier argument to _getHtml/_normalizeHtml * Use getAttribute for 'class' to support namespaced elements (e.g. svg) * Update format name * Add optional tag * Update docs
Diffstat (limited to 'ext')
-rw-r--r--ext/js/display/display-generator.js2
-rw-r--r--ext/js/display/sandbox/pronunciation-generator.js2
-rw-r--r--ext/js/dom/sandbox/css-style-applier.js2
-rw-r--r--ext/js/templates/sandbox/anki-template-renderer.js57
-rw-r--r--ext/template-renderer.html1
5 files changed, 52 insertions, 12 deletions
diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js
index 2421b88a..11a0a9d3 100644
--- a/ext/js/display/display-generator.js
+++ b/ext/js/display/display-generator.js
@@ -477,7 +477,7 @@ class DisplayGenerator {
this._createPitchAccentDisambiguations(n, exclusiveTerms, exclusiveReadings);
n = node.querySelector('.pronunciation-downstep-notation-container');
- n.appendChild(this._pronunciationGenerator.createPronunciationDownstepNotation(position));
+ n.appendChild(this._pronunciationGenerator.createPronunciationDownstepPosition(position));
n = node.querySelector('.pronunciation-text-container');
n.lang = 'ja';
diff --git a/ext/js/display/sandbox/pronunciation-generator.js b/ext/js/display/sandbox/pronunciation-generator.js
index bab36add..3739e716 100644
--- a/ext/js/display/sandbox/pronunciation-generator.js
+++ b/ext/js/display/sandbox/pronunciation-generator.js
@@ -144,7 +144,7 @@ class PronunciationGenerator {
return svg;
}
- createPronunciationDownstepNotation(downstepPosition) {
+ createPronunciationDownstepPosition(downstepPosition) {
downstepPosition = `${downstepPosition}`;
const n1 = document.createElement('span');
diff --git a/ext/js/dom/sandbox/css-style-applier.js b/ext/js/dom/sandbox/css-style-applier.js
index c617fead..84b8450b 100644
--- a/ext/js/dom/sandbox/css-style-applier.js
+++ b/ext/js/dom/sandbox/css-style-applier.js
@@ -54,7 +54,7 @@ class CssStyleApplier {
applyClassStyles(elements) {
const elementStyles = [];
for (const element of elements) {
- const {className} = element;
+ const className = element.getAttribute('class');
if (className.length === 0) { continue; }
let cssTextNew = '';
for (const {selectorText, styles} of this._getRulesForClass(className)) {
diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js
index 907ab0fa..43092ec2 100644
--- a/ext/js/templates/sandbox/anki-template-renderer.js
+++ b/ext/js/templates/sandbox/anki-template-renderer.js
@@ -21,6 +21,7 @@
* DictionaryDataUtil
* Handlebars
* JapaneseUtil
+ * PronunciationGenerator
* StructuredContentGenerator
* TemplateRenderer
* TemplateRendererMediaProvider
@@ -35,11 +36,13 @@ class AnkiTemplateRenderer {
* Creates a new instance of the class.
*/
constructor() {
- this._cssStyleApplier = new CssStyleApplier('/data/structured-content-style.json');
+ this._structuredContentStyleApplier = new CssStyleApplier('/data/structured-content-style.json');
+ this._pronunciationStyleApplier = new CssStyleApplier('/data/pronunciation-style.json');
this._japaneseUtil = new JapaneseUtil(null);
this._templateRenderer = new TemplateRenderer();
this._ankiNoteDataCreator = new AnkiNoteDataCreator(this._japaneseUtil);
this._mediaProvider = new TemplateRendererMediaProvider();
+ this._pronunciationGenerator = new PronunciationGenerator(this._japaneseUtil);
this._stateStack = null;
this._requirements = null;
this._cleanupCallbacks = null;
@@ -83,7 +86,8 @@ class AnkiTemplateRenderer {
['pitchCategories', this._pitchCategories.bind(this)],
['formatGlossary', this._formatGlossary.bind(this)],
['hasMedia', this._hasMedia.bind(this)],
- ['getMedia', this._getMedia.bind(this)]
+ ['getMedia', this._getMedia.bind(this)],
+ ['pronunciation', this._pronunciation.bind(this)]
]);
this._templateRenderer.registerDataType('ankiNote', {
modifier: ({marker, commonData}) => this._ankiNoteDataCreator.create(marker, commonData),
@@ -93,7 +97,10 @@ class AnkiTemplateRenderer {
this._onRenderSetup.bind(this),
this._onRenderCleanup.bind(this)
);
- await this._cssStyleApplier.prepare();
+ await Promise.all([
+ this._structuredContentStyleApplier.prepare(),
+ this._pronunciationStyleApplier.prepare()
+ ]);
}
// Private
@@ -453,16 +460,16 @@ class AnkiTemplateRenderer {
return element;
}
- _getHtml(node) {
+ _getHtml(node, styleApplier) {
const container = this._getTemporaryElement();
container.appendChild(node);
- this._normalizeHtml(container);
+ this._normalizeHtml(container, styleApplier);
const result = container.innerHTML;
container.textContent = '';
return result;
}
- _normalizeHtml(root) {
+ _normalizeHtml(root, styleApplier) {
const {ELEMENT_NODE, TEXT_NODE} = Node;
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
const elements = [];
@@ -479,7 +486,7 @@ class AnkiTemplateRenderer {
break;
}
}
- this._cssStyleApplier.applyClassStyles(elements);
+ styleApplier.applyClassStyles(elements);
for (const element of elements) {
const {dataset} = element;
for (const key of Object.keys(dataset)) {
@@ -532,13 +539,13 @@ class AnkiTemplateRenderer {
_formatGlossaryImage(content, dictionary, data) {
const structuredContentGenerator = this._createStructuredContentGenerator(data);
const node = structuredContentGenerator.createDefinitionImage(content, dictionary);
- return this._getHtml(node);
+ return this._getHtml(node, this._structuredContentStyleApplier);
}
_formatStructuredContent(content, dictionary, data) {
const structuredContentGenerator = this._createStructuredContentGenerator(data);
const node = structuredContentGenerator.createStructuredContent(content.content, dictionary);
- return node !== null ? this._getHtml(node) : '';
+ return node !== null ? this._getHtml(node, this._structuredContentStyleApplier) : '';
}
_hasMedia(context, ...args) {
@@ -552,4 +559,36 @@ class AnkiTemplateRenderer {
const options = args[ii];
return this._mediaProvider.getMedia(options.data.root, args.slice(0, ii), options.hash);
}
+
+ _pronunciation(context, ...args) {
+ const ii = args.length - 1;
+ const options = args[ii];
+ let {format, reading, downstepPosition, nasalPositions, devoicePositions} = options.hash;
+
+ if (typeof reading !== 'string' || reading.length === 0) { return ''; }
+ if (typeof downstepPosition !== 'number') { return ''; }
+ if (!Array.isArray(nasalPositions)) { nasalPositions = []; }
+ if (!Array.isArray(devoicePositions)) { devoicePositions = []; }
+ const morae = this._japaneseUtil.getKanaMorae(reading);
+
+ switch (format) {
+ case 'text':
+ return this._getHtml(
+ this._pronunciationGenerator.createPronunciationText(morae, downstepPosition, nasalPositions, devoicePositions),
+ this._pronunciationStyleApplier
+ );
+ case 'graph':
+ return this._getHtml(
+ this._pronunciationGenerator.createPronunciationGraph(morae, downstepPosition),
+ this._pronunciationStyleApplier
+ );
+ case 'position':
+ return this._getHtml(
+ this._pronunciationGenerator.createPronunciationDownstepPosition(downstepPosition),
+ this._pronunciationStyleApplier
+ );
+ default:
+ return '';
+ }
+ }
}
diff --git a/ext/template-renderer.html b/ext/template-renderer.html
index 2db61d05..19595ec4 100644
--- a/ext/template-renderer.html
+++ b/ext/template-renderer.html
@@ -18,6 +18,7 @@
<script src="/lib/handlebars.min.js"></script>
<script src="/js/data/sandbox/anki-note-data-creator.js"></script>
+<script src="/js/display/sandbox/pronunciation-generator.js"></script>
<script src="/js/display/sandbox/structured-content-generator.js"></script>
<script src="/js/dom/sandbox/css-style-applier.js"></script>
<script src="/js/language/sandbox/dictionary-data-util.js"></script>