Structured content data (#1930)

* Add support for structured-content data attributes

* Assign dataset properties

* Don't remove data-sc attributes

* Use helper functions

* Update test data
This commit is contained in:
toasted-nutbread 2021-09-04 12:43:56 -04:00 committed by GitHub
parent eb457caea9
commit f68ad1f843
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 17 deletions

View File

@ -28,6 +28,9 @@
"tag": {
"type": "string",
"enum": ["br"]
},
"data": {
"$ref": "#/definitions/structuredContentData"
}
}
},
@ -45,6 +48,9 @@
},
"content": {
"$ref": "#/definitions/structuredContent"
},
"data": {
"$ref": "#/definitions/structuredContentData"
}
}
},
@ -63,6 +69,9 @@
"content": {
"$ref": "#/definitions/structuredContent"
},
"data": {
"$ref": "#/definitions/structuredContentData"
},
"colSpan": {
"type": "integer",
"minimum": 1
@ -91,6 +100,9 @@
"content": {
"$ref": "#/definitions/structuredContent"
},
"data": {
"$ref": "#/definitions/structuredContentData"
},
"style": {
"$ref": "#/definitions/structuredContentStyle"
}
@ -109,6 +121,9 @@
"type": "string",
"const": "img"
},
"data": {
"$ref": "#/definitions/structuredContentData"
},
"path": {
"type": "string",
"description": "Path to the image file in the archive."
@ -175,6 +190,13 @@
}
]
},
"structuredContentData": {
"type": "object",
"description": "Generic data attributes that should be added to the element.",
"additionalProperties": {
"type": "string"
}
},
"structuredContentStyle": {
"type": "object",
"additionalProperties": false,

View File

@ -169,6 +169,16 @@ class StructuredContentGenerator {
return this._document.createDocumentFragment();
}
_setElementDataset(element, data) {
for (let [key, value] of Object.entries(data)) {
if (key.length > 0) {
key = `${key[0].toUpperCase()}${key.substring(1)}`;
}
key = `sc${key}`;
element.dataset[key] = value;
}
}
_setImageData(node, image, imageBackground, url, unloaded) {
if (url !== null) {
image.src = url;
@ -192,6 +202,8 @@ class StructuredContentGenerator {
_createStructuredContentElement(tag, content, dictionary, type, hasChildren, hasStyle) {
const node = this._createElement(tag, `gloss-sc-${tag}`);
const {data} = content;
if (typeof data === 'object' && data !== null) { this._setElementDataset(node, data); }
switch (type) {
case 'table-cell':
{

View File

@ -38,6 +38,7 @@ class AnkiTemplateRenderer {
constructor() {
this._structuredContentStyleApplier = new CssStyleApplier('/data/structured-content-style.json');
this._pronunciationStyleApplier = new CssStyleApplier('/data/pronunciation-style.json');
this._structuredContentDatasetKeyIgnorePattern = /^sc([^a-z]|$)/;
this._japaneseUtil = new JapaneseUtil(null);
this._templateRenderer = new TemplateRenderer();
this._ankiNoteDataCreator = new AnkiNoteDataCreator(this._japaneseUtil);
@ -462,16 +463,24 @@ class AnkiTemplateRenderer {
return element;
}
_getHtml(node, styleApplier) {
_getStructuredContentHtml(node) {
return this._getHtml(node, this._structuredContentStyleApplier, this._structuredContentDatasetKeyIgnorePattern);
}
_getPronunciationHtml(node) {
return this._getHtml(node, this._pronunciationStyleApplier, null);
}
_getHtml(node, styleApplier, datasetKeyIgnorePattern) {
const container = this._getTemporaryElement();
container.appendChild(node);
this._normalizeHtml(container, styleApplier);
this._normalizeHtml(container, styleApplier, datasetKeyIgnorePattern);
const result = container.innerHTML;
container.textContent = '';
return result;
}
_normalizeHtml(root, styleApplier) {
_normalizeHtml(root, styleApplier, datasetKeyIgnorePattern) {
const {ELEMENT_NODE, TEXT_NODE} = Node;
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
const elements = [];
@ -492,6 +501,7 @@ class AnkiTemplateRenderer {
for (const element of elements) {
const {dataset} = element;
for (const key of Object.keys(dataset)) {
if (datasetKeyIgnorePattern !== null && datasetKeyIgnorePattern.test(key)) { continue; }
delete dataset[key];
}
}
@ -541,13 +551,13 @@ class AnkiTemplateRenderer {
_formatGlossaryImage(content, dictionary, data) {
const structuredContentGenerator = this._createStructuredContentGenerator(data);
const node = structuredContentGenerator.createDefinitionImage(content, dictionary);
return this._getHtml(node, this._structuredContentStyleApplier);
return this._getStructuredContentHtml(node);
}
_formatStructuredContent(content, dictionary, data) {
const structuredContentGenerator = this._createStructuredContentGenerator(data);
const node = structuredContentGenerator.createStructuredContent(content.content, dictionary);
return node !== null ? this._getHtml(node, this._structuredContentStyleApplier) : '';
return node !== null ? this._getStructuredContentHtml(node) : '';
}
_hasMedia(context, ...args) {
@ -575,20 +585,11 @@ class AnkiTemplateRenderer {
switch (format) {
case 'text':
return this._getHtml(
this._pronunciationGenerator.createPronunciationText(morae, downstepPosition, nasalPositions, devoicePositions),
this._pronunciationStyleApplier
);
return this._getPronunciationHtml(this._pronunciationGenerator.createPronunciationText(morae, downstepPosition, nasalPositions, devoicePositions));
case 'graph':
return this._getHtml(
this._pronunciationGenerator.createPronunciationGraph(morae, downstepPosition),
this._pronunciationStyleApplier
);
return this._getPronunciationHtml(this._pronunciationGenerator.createPronunciationGraph(morae, downstepPosition));
case 'position':
return this._getHtml(
this._pronunciationGenerator.createPronunciationDownstepPosition(downstepPosition),
this._pronunciationStyleApplier
);
return this._getPronunciationHtml(this._pronunciationGenerator.createPronunciationDownstepPosition(downstepPosition));
default:
return '';
}

View File

@ -164,6 +164,21 @@
]
},
"margin"
]},
{"type": "structured-content", "content": [
"text 1 ",
{
"tag": "span",
"data": {
"": "empty",
"a": "b",
"c": "d"
},
"content": [
"text 2"
]
},
" text 3"
]}
],
100, "P E1"