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:
parent
eb457caea9
commit
f68ad1f843
@ -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,
|
||||||
|
@ -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':
|
||||||
{
|
{
|
||||||
|
@ -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 '';
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user