aboutsummaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/display/display-generator.js51
-rw-r--r--ext/js/language/dictionary-importer.js50
2 files changed, 94 insertions, 7 deletions
diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js
index 299d730b..2131d805 100644
--- a/ext/js/display/display-generator.js
+++ b/ext/js/display/display-generator.js
@@ -295,6 +295,8 @@ class DisplayGenerator {
switch (entry.type) {
case 'image':
return this._createTermDefinitionEntryImage(entry, dictionary);
+ case 'structured-content':
+ return this._createTermDefinitionEntryStructuredContent(entry.content, dictionary);
}
}
@@ -327,8 +329,18 @@ class DisplayGenerator {
return node;
}
+ _createTermDefinitionEntryStructuredContent(content, dictionary) {
+ const node = this._templates.instantiate('gloss-item');
+ const child = this._createStructuredContent(content, dictionary);
+ if (child !== null) {
+ const contentContainer = node.querySelector('.gloss-content');
+ contentContainer.appendChild(child);
+ }
+ return node;
+ }
+
_createDefinitionImage(data, dictionary) {
- const {path, width, height, preferredWidth, preferredHeight, title, pixelated, collapsed, collapsible} = data;
+ const {path, width, height, preferredWidth, preferredHeight, title, pixelated, collapsed, collapsible, verticalAlign} = data;
const usedWidth = (
typeof preferredWidth === 'number' ?
@@ -349,6 +361,9 @@ class DisplayGenerator {
node.dataset.hasAspectRatio = '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;
+ }
const imageContainer = node.querySelector('.gloss-image-container');
imageContainer.style.width = `${usedWidth}em`;
@@ -386,6 +401,40 @@ class DisplayGenerator {
}
}
+ _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 'ruby':
+ case 'rt':
+ case 'rp':
+ {
+ const node = document.createElement(tag);
+ const child = this._createStructuredContent(content.content, dictionary);
+ if (child !== null) {
+ node.appendChild(child);
+ }
+ return node;
+ }
+ case 'img':
+ return this._createDefinitionImage(content, dictionary);
+ }
+ return null;
+ }
+
_createTermDisambiguation(disambiguation) {
const node = this._templates.instantiate('definition-disambiguation');
node.dataset.term = disambiguation;
diff --git a/ext/js/language/dictionary-importer.js b/ext/js/language/dictionary-importer.js
index 051375a0..4d885a74 100644
--- a/ext/js/language/dictionary-importer.js
+++ b/ext/js/language/dictionary-importer.js
@@ -300,20 +300,58 @@ class DictionaryImporter {
return data.text;
case 'image':
return await this._formatDictionaryTermGlossaryImage(data, context, entry);
+ case 'structured-content':
+ return await this._formatStructuredContent(data, context, entry);
default:
throw new Error(`Unhandled data type: ${data.type}`);
}
}
async _formatDictionaryTermGlossaryImage(data, context, entry) {
+ return await this._createImageData(data, context, entry, {type: 'image'});
+ }
+
+ async _formatStructuredContent(data, context, entry) {
+ const content = await this._prepareStructuredContent(data.content, context, entry);
+ return {
+ type: 'structured-content',
+ content
+ };
+ }
+
+ async _prepareStructuredContent(content, context, entry) {
+ if (typeof content === 'string' || !(typeof content === 'object' && content !== null)) {
+ return content;
+ }
+ if (Array.isArray(content)) {
+ for (let i = 0, ii = content.length; i < ii; ++i) {
+ content[i] = await this._prepareStructuredContent(content[i], context, entry);
+ }
+ return content;
+ }
+ const {tag} = content;
+ switch (tag) {
+ case 'img':
+ return await this._prepareStructuredContentImage(content, context, entry);
+ }
+ const childContent = content.content;
+ if (typeof childContent !== 'undefined') {
+ content.content = await this._prepareStructuredContent(childContent, context, entry);
+ }
+ return content;
+ }
+
+ async _prepareStructuredContentImage(content, context, entry) {
+ const {verticalAlign} = content;
+ const result = await this._createImageData(content, context, entry, {tag: 'img'});
+ if (typeof verticalAlign === 'string') { result.verticalAlign = verticalAlign; }
+ return result;
+ }
+
+ async _createImageData(data, context, entry, attributes) {
const {path, width: preferredWidth, height: preferredHeight, title, description, pixelated, collapsed, collapsible} = data;
const {width, height} = await this._getImageMedia(path, context, entry);
- const newData = {
- type: 'image',
- path,
- width,
- height
- };
+ const newData = Object.assign({}, attributes, {path, width, height});
if (typeof preferredWidth === 'number') { newData.preferredWidth = preferredWidth; }
if (typeof preferredHeight === 'number') { newData.preferredHeight = preferredHeight; }
if (typeof title === 'string') { newData.title = title; }