From d9955f70a8104e8d9224f79290804fd885d05747 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Fri, 29 Apr 2022 09:32:37 -0500 Subject: [PATCH 1/4] Add support for structured content lists and `list-style-type` style A full list of supported style types is documented here: https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-type There's nothing in this code preventing a term bank from assigning, for example, a `list-style-type` style to a `div` element, but it doesn't seem like browsers will complain about things like that. --- .../dictionary-term-bank-v3-schema.json | 6 ++- .../sandbox/structured-content-generator.js | 7 +++- .../valid-dictionary1/term_bank_1.json | 37 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ext/data/schemas/dictionary-term-bank-v3-schema.json b/ext/data/schemas/dictionary-term-bank-v3-schema.json index 268a2c11cc..5abbf43b76 100644 --- a/ext/data/schemas/dictionary-term-bank-v3-schema.json +++ b/ext/data/schemas/dictionary-term-bank-v3-schema.json @@ -95,7 +95,7 @@ "properties": { "tag": { "type": "string", - "enum": ["span", "div"] + "enum": ["span", "div", "ol", "ul", "li"] }, "content": { "$ref": "#/definitions/structuredContent" @@ -276,6 +276,10 @@ "marginBottom": { "type": "number", "default": 0 + }, + "listStyleType": { + "type": "string", + "default": "disc" } } } diff --git a/ext/js/display/sandbox/structured-content-generator.js b/ext/js/display/sandbox/structured-content-generator.js index eb847d07d1..61e4509257 100644 --- a/ext/js/display/sandbox/structured-content-generator.js +++ b/ext/js/display/sandbox/structured-content-generator.js @@ -56,6 +56,9 @@ class StructuredContentGenerator { return this._createStructuredContentElement(tag, content, dictionary, 'table-cell', true, true); case 'div': case 'span': + case 'ol': + case 'ul': + case 'li': return this._createStructuredContentElement(tag, content, dictionary, 'simple', true, true); case 'img': return this.createDefinitionImage(content, dictionary); @@ -239,7 +242,8 @@ class StructuredContentGenerator { marginTop, marginLeft, marginRight, - marginBottom + marginBottom, + listStyleType } = contentStyle; if (typeof fontStyle === 'string') { style.fontStyle = fontStyle; } if (typeof fontWeight === 'string') { style.fontWeight = fontWeight; } @@ -254,6 +258,7 @@ class StructuredContentGenerator { if (typeof marginLeft === 'number') { style.marginLeft = `${marginLeft}em`; } if (typeof marginRight === 'number') { style.marginRight = `${marginRight}em`; } if (typeof marginBottom === 'number') { style.marginBottom = `${marginBottom}em`; } + if (typeof listStyleType === 'string') { style.listStyleType = listStyleType; } } _createLinkElement(content, dictionary) { diff --git a/test/data/dictionaries/valid-dictionary1/term_bank_1.json b/test/data/dictionaries/valid-dictionary1/term_bank_1.json index e75062551e..a4d0af7a29 100644 --- a/test/data/dictionaries/valid-dictionary1/term_bank_1.json +++ b/test/data/dictionaries/valid-dictionary1/term_bank_1.json @@ -204,6 +204,43 @@ "external link" ] } + ]}, + {"type": "structured-content", "content": [ + {"tag": "ul", "content": [ + {"tag": "li", "content": "Unordered list item 1"}, + {"tag": "li", "content": "Unordered list item 2"}, + {"tag": "li", "content": "Unordered list item 3"} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "ol", "content": [ + {"tag": "li", "content": "Ordered list item 1"}, + {"tag": "li", "content": "Ordered list item 2"}, + {"tag": "li", "content": "Ordered list item 3"} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "ol", "style": {"listStyleType": "hiragana-iroha"}, "content": [ + {"tag": "li", "content": "List item i"}, + {"tag": "li", "content": "List item ro"}, + {"tag": "li", "content": "List item ha"} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "ul", "content": [ + {"tag": "li", "style": {"listStyleType": "'⇄'"}, "content": ["【", {"tag": "a", "href": "?query=よみ&wildcards=off", "content": ["Antonym"]}, "】"]}, + {"tag": "li", "style": {"listStyleType": "'🔄'"}, "content": ["【", {"tag": "a", "href": "?query=よみ&wildcards=off", "content": ["References and is referenced by"]}, "】"]}, + {"tag": "li", "style": {"listStyleType": "'➡'"}, "content": ["【", {"tag": "a", "href": "?query=よみ&wildcards=off", "content": ["References"]}, "】"]}, + {"tag": "li", "style": {"listStyleType": "'⬅'"}, "content": ["【", {"tag": "a", "href": "?query=よみ&wildcards=off", "content": ["Referenced by"]}, "】"]} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "ol", "content": [ + {"tag": "li", "style": {"listStyleType": "'①'"}, "content": "まるいち"}, + {"tag": "li", "style": {"listStyleType": "'②'"}, "content": "まるに"}, + {"tag": "li", "style": {"listStyleType": "'③'"}, "content": "まるさん"}, + {"tag": "li", "style": {"listStyleType": "'④'"}, "content": "まるよん"} + ]} ]} ], 100, "P E1" From 360f09d12386bfe3976194617d70474df3512752 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Fri, 29 Apr 2022 09:35:49 -0500 Subject: [PATCH 2/4] Add support for `lang` attribute in structured content Support added for the following node types: "ruby", "rt", "rp", "table", "thead", "tbody", "tfoot", "tr", "td", "th", "span", "div", "ol", "ul", "li", "a" I couldn't get it to work for the alt-hover text on "img" tags. Tests are included in the file "test/data/dictionaries/valid-dictionary/term_bank_1.json" --- .../dictionary-term-bank-v3-schema.json | 16 +++++ .../sandbox/structured-content-generator.js | 6 +- .../valid-dictionary1/term_bank_1.json | 62 +++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/ext/data/schemas/dictionary-term-bank-v3-schema.json b/ext/data/schemas/dictionary-term-bank-v3-schema.json index 5abbf43b76..2ddde52014 100644 --- a/ext/data/schemas/dictionary-term-bank-v3-schema.json +++ b/ext/data/schemas/dictionary-term-bank-v3-schema.json @@ -51,6 +51,10 @@ }, "data": { "$ref": "#/definitions/structuredContentData" + }, + "lang": { + "type": "string", + "description": "Defines the language of an element in the format defined by RFC 5646" } } }, @@ -82,6 +86,10 @@ }, "style": { "$ref": "#/definitions/structuredContentStyle" + }, + "lang": { + "type": "string", + "description": "Defines the language of an element in the format defined by RFC 5646" } } }, @@ -105,6 +113,10 @@ }, "style": { "$ref": "#/definitions/structuredContentStyle" + }, + "lang": { + "type": "string", + "description": "Defines the language of an element in the format defined by RFC 5646" } } }, @@ -206,6 +218,10 @@ "type": "string", "description": "The URL for the link. URLs starting with a ? are treated as internal links to other dictionary content.", "pattern": "^(?:https?:|\\?)[\\w\\W]*" + }, + "lang": { + "type": "string", + "description": "Defines the language of an element in the format defined by RFC 5646" } } } diff --git a/ext/js/display/sandbox/structured-content-generator.js b/ext/js/display/sandbox/structured-content-generator.js index 61e4509257..6102cfddc6 100644 --- a/ext/js/display/sandbox/structured-content-generator.js +++ b/ext/js/display/sandbox/structured-content-generator.js @@ -207,8 +207,9 @@ class StructuredContentGenerator { _createStructuredContentElement(tag, content, dictionary, type, hasChildren, hasStyle) { const node = this._createElement(tag, `gloss-sc-${tag}`); - const {data} = content; + const {data, lang} = content; if (typeof data === 'object' && data !== null) { this._setElementDataset(node, data); } + if (typeof lang === 'string') { node.lang = lang; } switch (type) { case 'table-cell': { @@ -274,6 +275,9 @@ class StructuredContentGenerator { const text = this._createElement('span', 'gloss-link-text'); node.appendChild(text); + const {lang} = content; + if (typeof lang === 'string') { node.lang = lang; } + const child = this.createStructuredContent(content.content, dictionary); if (child !== null) { text.appendChild(child); } diff --git a/test/data/dictionaries/valid-dictionary1/term_bank_1.json b/test/data/dictionaries/valid-dictionary1/term_bank_1.json index a4d0af7a29..cdff4028ef 100644 --- a/test/data/dictionaries/valid-dictionary1/term_bank_1.json +++ b/test/data/dictionaries/valid-dictionary1/term_bank_1.json @@ -241,6 +241,68 @@ {"tag": "li", "style": {"listStyleType": "'③'"}, "content": "まるさん"}, {"tag": "li", "style": {"listStyleType": "'④'"}, "content": "まるよん"} ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "div", "lang": "?????", "style": {"fontSize": "xxx-large"}, "content": "直次茶冷 (invalid lang)"}, + {"tag": "div", "lang": "ja-JP", "style": {"fontSize": "xxx-large"}, "content": "直次茶冷 (lang=ja-JP)"}, + {"tag": "div", "lang": "zh-CN", "style": {"fontSize": "xxx-large"}, "content": "直次茶冷 (lang=zh-CN)"}, + {"tag": "div", "lang": "zh-TW", "style": {"fontSize": "xxx-large"}, "content": "直次茶冷 (lang=zh-TW)"} + ]}, + {"type": "structured-content", "content": [ + {"tag": "ul", "style": {"listStyleType": "japanese-formal"}, "content": [ + {"tag": "li", "content": ["【", {"tag": "a", "href": "?query=直次茶冷&wildcards=off", "content": "直次茶冷"}, "】(default)"]}, + {"tag": "li", "content": ["【", {"tag": "a", "href": "?query=直次茶冷&wildcards=off", "content": "直次茶冷", "lang": "ja"}, "】(lang=ja)"]}, + {"tag": "li", "content": ["【", {"tag": "a", "href": "?query=直次茶冷&wildcards=off", "content": "直次茶冷", "lang": "zh-CN"}, "】(lang=zh-CN)"]}, + {"tag": "li", "content": ["【", {"tag": "a", "href": "?query=直次茶冷&wildcards=off", "content": "直次茶冷", "lang": "zh-TW"}, "】(lang=zh-TW)"]} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "table", "lang": "", "content": [ + {"tag": "thead", "content": [ + {"tag": "tr", "content": [ + {"tag": "th", "content": "JP"}, + {"tag": "th", "content": "SC"}, + {"tag": "th", "content": "TC"}, + {"tag": "th", "content": "??"} + ]} + ]}, + {"tag": "tbody", "content": [ + {"tag": "tr", "content": [ + {"tag": "td", "lang": "ja-JP", "content": "直次茶冷"}, + {"tag": "td", "lang": "zh-CN", "content": "直次茶冷"}, + {"tag": "td", "lang": "zh-TW", "content": "直次茶冷"}, + {"tag": "td", "content": "直次茶冷"} + ]} + ]} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "table", "lang": "ja", "content": [ + {"tag": "thead", "content": [ + {"tag": "tr", "content": [ + {"tag": "th", "content": "lang=ja applied to whole table"} + ]} + ]}, + {"tag": "tbody", "content": [ + {"tag": "tr", "content": [ + {"tag": "td", "content": "直次茶冷"} + ]} + ]} + ]} + ]}, + {"type": "structured-content", "content": [ + {"tag": "table", "lang": "zh-CN", "content": [ + {"tag": "thead", "content": [ + {"tag": "tr", "content": [ + {"tag": "th", "content": "lang=zh-CN applied to whole table"} + ]} + ]}, + {"tag": "tbody", "content": [ + {"tag": "tr", "content": [ + {"tag": "td", "content": "直次茶冷"} + ]} + ]} + ]} ]} ], 100, "P E1" From 5d57f587f37a43a39c91d347187542f2f3bcdc10 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Fri, 13 May 2022 13:57:27 -0500 Subject: [PATCH 3/4] Add styles for structured content lists --- ext/css/structured-content.css | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ext/css/structured-content.css b/ext/css/structured-content.css index 485527e548..2d3cf8bab1 100644 --- a/ext/css/structured-content.css +++ b/ext/css/structured-content.css @@ -235,3 +235,23 @@ padding: 0.25em; vertical-align: top; } +.gloss-sc-ol { + padding-left: var(--list-padding2); +} +.gloss-sc-ul { + padding-left: var(--list-padding2); +} +:root[data-glossary-layout-mode=compact] .gloss-sc-ul[data-sc-content=glossary] { + display: inline; + list-style: none; + padding-left: 0; +} +:root[data-glossary-layout-mode=compact] .gloss-sc-ul[data-sc-content=glossary] .gloss-sc-li { + display: inline; +} +:root[data-glossary-layout-mode=compact] .gloss-sc-ul[data-sc-content=glossary] .gloss-sc-li:not(:first-child)::before { + white-space: pre-wrap; + content: var(--compact-list-separator); + display: inline; + color: var(--text-color-light3); +} From 51f618905270bdde6a19b4c767980734eda5c30a Mon Sep 17 00:00:00 2001 From: stephenmk Date: Fri, 13 May 2022 17:50:13 -0500 Subject: [PATCH 4/4] Add override rules for new structured-content list styles see: https://github.com/FooSoft/yomichan/pull/2129 --- dev/data/structured-content-overrides.css | 13 +++++++++++++ ext/css/structured-content.css | 4 +--- .../schemas/dictionary-term-bank-v3-schema.json | 8 ++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/dev/data/structured-content-overrides.css b/dev/data/structured-content-overrides.css index 9fd08f8f85..811ed9cf63 100644 --- a/dev/data/structured-content-overrides.css +++ b/dev/data/structured-content-overrides.css @@ -61,3 +61,16 @@ display: none; /* remove-property background-color vertical-align width height margin-left background-color position */ } +.gloss-sc-ol, +.gloss-sc-ul { + /* remove-property padding-left */ +} +:root[data-glossary-layout-mode=compact] .gloss-sc-ul[data-sc-content=glossary] { + /* remove-rule */ +} +:root[data-glossary-layout-mode=compact] .gloss-sc-ul[data-sc-content=glossary] .gloss-sc-li { + /* remove-rule */ +} +:root[data-glossary-layout-mode=compact] .gloss-sc-ul[data-sc-content=glossary] .gloss-sc-li:not(:first-child)::before { + /* remove-rule */ +} diff --git a/ext/css/structured-content.css b/ext/css/structured-content.css index 2d3cf8bab1..5e86331806 100644 --- a/ext/css/structured-content.css +++ b/ext/css/structured-content.css @@ -235,9 +235,7 @@ padding: 0.25em; vertical-align: top; } -.gloss-sc-ol { - padding-left: var(--list-padding2); -} +.gloss-sc-ol, .gloss-sc-ul { padding-left: var(--list-padding2); } diff --git a/ext/data/schemas/dictionary-term-bank-v3-schema.json b/ext/data/schemas/dictionary-term-bank-v3-schema.json index 2ddde52014..12c2e4f3e4 100644 --- a/ext/data/schemas/dictionary-term-bank-v3-schema.json +++ b/ext/data/schemas/dictionary-term-bank-v3-schema.json @@ -54,7 +54,7 @@ }, "lang": { "type": "string", - "description": "Defines the language of an element in the format defined by RFC 5646" + "description": "Defines the language of an element in the format defined by RFC 5646." } } }, @@ -89,7 +89,7 @@ }, "lang": { "type": "string", - "description": "Defines the language of an element in the format defined by RFC 5646" + "description": "Defines the language of an element in the format defined by RFC 5646." } } }, @@ -116,7 +116,7 @@ }, "lang": { "type": "string", - "description": "Defines the language of an element in the format defined by RFC 5646" + "description": "Defines the language of an element in the format defined by RFC 5646." } } }, @@ -221,7 +221,7 @@ }, "lang": { "type": "string", - "description": "Defines the language of an element in the format defined by RFC 5646" + "description": "Defines the language of an element in the format defined by RFC 5646." } } }