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": { "tag": {
"type": "string", "type": "string",
"enum": ["br"] "enum": ["br"]
},
"data": {
"$ref": "#/definitions/structuredContentData"
} }
} }
}, },
@ -45,6 +48,9 @@
}, },
"content": { "content": {
"$ref": "#/definitions/structuredContent" "$ref": "#/definitions/structuredContent"
},
"data": {
"$ref": "#/definitions/structuredContentData"
} }
} }
}, },
@ -63,6 +69,9 @@
"content": { "content": {
"$ref": "#/definitions/structuredContent" "$ref": "#/definitions/structuredContent"
}, },
"data": {
"$ref": "#/definitions/structuredContentData"
},
"colSpan": { "colSpan": {
"type": "integer", "type": "integer",
"minimum": 1 "minimum": 1
@ -91,6 +100,9 @@
"content": { "content": {
"$ref": "#/definitions/structuredContent" "$ref": "#/definitions/structuredContent"
}, },
"data": {
"$ref": "#/definitions/structuredContentData"
},
"style": { "style": {
"$ref": "#/definitions/structuredContentStyle" "$ref": "#/definitions/structuredContentStyle"
} }
@ -109,6 +121,9 @@
"type": "string", "type": "string",
"const": "img" "const": "img"
}, },
"data": {
"$ref": "#/definitions/structuredContentData"
},
"path": { "path": {
"type": "string", "type": "string",
"description": "Path to the image file in the archive." "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": { "structuredContentStyle": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,

View File

@ -169,6 +169,16 @@ class StructuredContentGenerator {
return this._document.createDocumentFragment(); 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) { _setImageData(node, image, imageBackground, url, unloaded) {
if (url !== null) { if (url !== null) {
image.src = url; image.src = url;
@ -192,6 +202,8 @@ class StructuredContentGenerator {
_createStructuredContentElement(tag, content, dictionary, type, hasChildren, hasStyle) { _createStructuredContentElement(tag, content, dictionary, type, hasChildren, hasStyle) {
const node = this._createElement(tag, `gloss-sc-${tag}`); const node = this._createElement(tag, `gloss-sc-${tag}`);
const {data} = content;
if (typeof data === 'object' && data !== null) { this._setElementDataset(node, data); }
switch (type) { switch (type) {
case 'table-cell': case 'table-cell':
{ {

View File

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

View File

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