From 7ae964c8300092040583bdc341525c6579f76e5c Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 6 Jun 2021 14:47:48 -0400 Subject: [PATCH] Structured content updates (#1733) * Add support for imageRendering * Make crisp-edges appearance on Firefox more similar to Chrome * Refactor * Add background option * Move data-image-rendering attribute * Restructure * Organize * Add support for appearance * Update test dictionary * Update tests --- ext/css/display.css | 37 ++++++++++++++++- .../dictionary-term-bank-v3-schema.json | 34 ++++++++++++++++ ext/display-templates.html | 10 ++++- ext/js/display/display-generator.js | 38 +++++++++++++----- ext/js/display/display.js | 4 ++ ext/js/language/dictionary-importer.js | 17 +++++++- .../valid-dictionary1/character.gif | Bin 0 -> 107 bytes .../valid-dictionary1/term_bank_1.json | 23 +++++++++++ test/test-database.js | 4 +- 9 files changed, 153 insertions(+), 14 deletions(-) create mode 100644 test/data/dictionaries/valid-dictionary1/character.gif diff --git a/ext/css/display.css b/ext/css/display.css index ac9dae0a..45658f19 100644 --- a/ext/css/display.css +++ b/ext/css/display.css @@ -1566,6 +1566,8 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con line-height: 0; font-size: calc(1em / var(--font-size-no-units)); overflow: hidden; +} +.gloss-image-link[data-background=true]>.gloss-image-container { background-color: var(--gloss-image-background-color); } .gloss-image-link { @@ -1600,6 +1602,18 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con text-align: center; padding: 0.25em; } +.gloss-image-background { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: var(--text-color); + + --image: none; + --icon-size: contain; + --icon-image: var(--image); +} .gloss-image { display: inline-block; vertical-align: top; @@ -1617,13 +1631,27 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con .gloss-image:not([src]) { display: none; } -.gloss-image[data-pixelated=true] { +.gloss-image-link[data-image-rendering=pixelated] .gloss-image, +.gloss-image-link[data-image-rendering=pixelated] .gloss-image-background { image-rendering: auto; image-rendering: -moz-crisp-edges; image-rendering: -webkit-optimize-contrast; image-rendering: pixelated; image-rendering: crisp-edges; } +.gloss-image-link[data-image-rendering=crisp-edges] .gloss-image, +.gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background { + image-rendering: auto; + image-rendering: -moz-crisp-edges; + image-rendering: -webkit-optimize-contrast; + image-rendering: crisp-edges; +} +:root[data-browser=firefox] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image, +:root[data-browser=firefox] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background, +:root[data-browser=firefox-mobile] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image, +:root[data-browser=firefox-mobile] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background { + image-rendering: auto; +} .gloss-image-link[data-has-aspect-ratio=true] .gloss-image-aspect-ratio-sizer { display: inline-block; width: 0; @@ -1645,6 +1673,13 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con white-space: pre-line; } +.gloss-image-link[data-appearance=monochrome] .gloss-image { + visibility: hidden; +} +.gloss-image-link:not([data-appearance=monochrome]) .gloss-image-background { + display: none; +} + .gloss-image-link[data-size-units=em] .gloss-image-container { font-size: 1em; } diff --git a/ext/data/schemas/dictionary-term-bank-v3-schema.json b/ext/data/schemas/dictionary-term-bank-v3-schema.json index 9003cbf3..fd3f3844 100644 --- a/ext/data/schemas/dictionary-term-bank-v3-schema.json +++ b/ext/data/schemas/dictionary-term-bank-v3-schema.json @@ -70,6 +70,23 @@ "description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.", "default": false }, + "imageRendering": { + "type": "string", + "description": "Controls how the image is rendered. The value of this field supersedes the pixelated field.", + "enum": ["auto", "pixelated", "crisp-edges"], + "default": "auto" + }, + "appearance": { + "type": "string", + "description": "Controls the appearance of the image. The \"monochrome\" value will mask the opaque parts of the image using the current text color.", + "enum": ["auto", "monochrome"], + "default": "auto" + }, + "background": { + "type": "boolean", + "description": "Whether or not a background color is displayed behind the image.", + "default": true + }, "collapsed": { "type": "boolean", "description": "Whether or not the image is collapsed by default.", @@ -219,6 +236,23 @@ "description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.", "default": false }, + "imageRendering": { + "type": "string", + "description": "Controls how the image is rendered. The value of this field supersedes the pixelated field.", + "enum": ["auto", "pixelated", "crisp-edges"], + "default": "auto" + }, + "appearance": { + "type": "string", + "description": "Controls the appearance of the image. The \"monochrome\" value will mask the opaque parts of the image using the current text color.", + "enum": ["auto", "monochrome"], + "default": "auto" + }, + "background": { + "type": "boolean", + "description": "Whether or not a background color is displayed behind the image.", + "default": true + }, "collapsed": { "type": "boolean", "description": "Whether or not the image is collapsed by default.", diff --git a/ext/display-templates.html b/ext/display-templates.html index 61d55638..0ad02748 100644 --- a/ext/display-templates.html +++ b/ext/display-templates.html @@ -57,7 +57,15 @@ - + diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index 484dc6a9..6a5b26f1 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -340,7 +340,22 @@ class DisplayGenerator { } _createDefinitionImage(data, dictionary) { - const {path, width, height, preferredWidth, preferredHeight, title, pixelated, collapsed, collapsible, verticalAlign, sizeUnits} = data; + const { + path, + width, + height, + preferredWidth, + preferredHeight, + title, + pixelated, + imageRendering, + appearance, + background, + collapsed, + collapsible, + verticalAlign, + sizeUnits + } = data; const hasPreferredWidth = (typeof preferredWidth === 'number'); const hasPreferredHeight = (typeof preferredHeight === 'number'); @@ -356,10 +371,18 @@ class DisplayGenerator { ); const node = this._templates.instantiate('gloss-item-image'); + const imageContainer = node.querySelector('.gloss-image-container'); + const aspectRatioSizer = node.querySelector('.gloss-image-aspect-ratio-sizer'); + const image = node.querySelector('.gloss-image'); + const imageBackground = node.querySelector('.gloss-image-background'); + node.dataset.path = path; node.dataset.dictionary = dictionary; node.dataset.imageLoadState = 'not-loaded'; node.dataset.hasAspectRatio = 'true'; + node.dataset.imageRendering = typeof imageRendering === 'string' ? imageRendering : (pixelated ? 'pixelated' : 'auto'); + node.dataset.appearance = typeof appearance === 'string' ? appearance : 'auto'; + node.dataset.background = typeof background === 'boolean' ? `${background}` : 'true'; node.dataset.collapsed = typeof collapsed === 'boolean' ? `${collapsed}` : 'false'; node.dataset.collapsible = typeof collapsible === 'boolean' ? `${collapsible}` : 'true'; if (typeof verticalAlign === 'string') { @@ -369,39 +392,36 @@ class DisplayGenerator { node.dataset.sizeUnits = sizeUnits; } - const imageContainer = node.querySelector('.gloss-image-container'); imageContainer.style.width = `${usedWidth}em`; if (typeof title === 'string') { imageContainer.title = title; } - const aspectRatioSizer = node.querySelector('.gloss-image-aspect-ratio-sizer'); aspectRatioSizer.style.paddingTop = `${aspectRatio * 100.0}%`; - const image = node.querySelector('img.gloss-image'); - image.dataset.pixelated = `${pixelated === true}`; - if (this._mediaLoader !== null) { this._mediaLoader.loadMedia( path, dictionary, - (url) => this._setImageData(node, image, url, false), - () => this._setImageData(node, image, null, true) + (url) => this._setImageData(node, image, imageBackground, url, false), + () => this._setImageData(node, image, imageBackground, null, true) ); } return node; } - _setImageData(node, image, url, unloaded) { + _setImageData(node, image, imageBackground, url, unloaded) { if (url !== null) { image.src = url; node.href = url; node.dataset.imageLoadState = 'loaded'; + imageBackground.style.setProperty('--image', `url("${url}")`); } else { image.removeAttribute('src'); node.removeAttribute('href'); node.dataset.imageLoadState = unloaded ? 'unloaded' : 'load-error'; + imageBackground.style.removeProperty('--image'); } } diff --git a/ext/js/display/display.js b/ext/js/display/display.js index ccca8229..26c1e06c 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -208,6 +208,10 @@ class Display extends EventDispatcher { const {browser} = await yomichan.api.getEnvironmentInfo(); this._browser = browser; + if (documentElement !== null) { + documentElement.dataset.browser = browser; + } + // Prepare await this._hotkeyHelpController.prepare(); await this._displayGenerator.prepare(); diff --git a/ext/js/language/dictionary-importer.js b/ext/js/language/dictionary-importer.js index a0806a3a..b735953a 100644 --- a/ext/js/language/dictionary-importer.js +++ b/ext/js/language/dictionary-importer.js @@ -361,7 +361,19 @@ class DictionaryImporter { } async _createImageData(data, context, entry, attributes) { - const {path, width: preferredWidth, height: preferredHeight, title, description, pixelated, collapsed, collapsible} = data; + const { + path, + width: preferredWidth, + height: preferredHeight, + title, + description, + pixelated, + imageRendering, + appearance, + background, + collapsed, + collapsible + } = data; const {width, height} = await this._getImageMedia(path, context, entry); const newData = Object.assign({}, attributes, {path, width, height}); if (typeof preferredWidth === 'number') { newData.preferredWidth = preferredWidth; } @@ -369,6 +381,9 @@ class DictionaryImporter { if (typeof title === 'string') { newData.title = title; } if (typeof description === 'string') { newData.description = description; } if (typeof pixelated === 'boolean') { newData.pixelated = pixelated; } + if (typeof imageRendering === 'string') { newData.imageRendering = imageRendering; } + if (typeof appearance === 'string') { newData.appearance = appearance; } + if (typeof background === 'boolean') { newData.background = background; } if (typeof collapsed === 'boolean') { newData.collapsed = collapsed; } if (typeof collapsible === 'boolean') { newData.collapsible = collapsible; } return newData; diff --git a/test/data/dictionaries/valid-dictionary1/character.gif b/test/data/dictionaries/valid-dictionary1/character.gif new file mode 100644 index 0000000000000000000000000000000000000000..9d5edad850098741a9c1e8dbb868d9a081c16cf0 GIT binary patch literal 107 zcmZ?wbhEHblwgoxXkcUjg8%>jEB<6*p4DY#+P;Jdp6wZIsEO}rQk}T-j;&_>18hWQbcbV1b<0gvOsq0F7B-D I%b6Ig0mCROS^xk5 literal 0 HcmV?d00001 diff --git a/test/data/dictionaries/valid-dictionary1/term_bank_1.json b/test/data/dictionaries/valid-dictionary1/term_bank_1.json index 0df04ef0..1ba70c26 100644 --- a/test/data/dictionaries/valid-dictionary1/term_bank_1.json +++ b/test/data/dictionaries/valid-dictionary1/term_bank_1.json @@ -36,6 +36,29 @@ "naiyou definition 6: ", {"tag": "ruby", "content": ["内", {"tag": "rp", "content": "("}, {"tag": "rt", "content": "ない"}, {"tag": "rp", "content": ")"}]}, {"tag": "ruby", "content": ["容", {"tag": "rp", "content": "("}, {"tag": "rt", "content": "よう"}, {"tag": "rp", "content": ")"}]} + ]}, + {"type": "structured-content", "content": [ + "imageRendering=auto: ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "auto", "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢 ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "auto", "background": false, "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢 ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "auto", "background": false, "appearance": "monochrome", "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢\n", + "imageRendering=pixelated: ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "pixelated", "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢 ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "pixelated", "background": false, "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢 ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "pixelated", "background": false, "appearance": "monochrome", "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢\n", + "imageRendering=crisp-edges: ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "crisp-edges", "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢 ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "crisp-edges", "background": false, "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢 ", + {"tag": "img", "path": "character.gif", "width": 1, "height": 1, "imageRendering": "crisp-edges", "background": false, "appearance": "monochrome", "collapsible": false, "collapsed": false, "sizeUnits": "em"}, + "莢\n" ]} ], 9, "P E1" diff --git a/test/test-database.js b/test/test-database.js index e68a39ba..d4005364 100644 --- a/test/test-database.js +++ b/test/test-database.js @@ -162,8 +162,8 @@ async function testDatabase1() { true ); vm.assert.deepStrictEqual(counts, { - counts: [{kanji: 2, kanjiMeta: 2, terms: 15, termMeta: 12, tagMeta: 15, media: 1}], - total: {kanji: 2, kanjiMeta: 2, terms: 15, termMeta: 12, tagMeta: 15, media: 1} + counts: [{kanji: 2, kanjiMeta: 2, terms: 15, termMeta: 12, tagMeta: 15, media: 2}], + total: {kanji: 2, kanjiMeta: 2, terms: 15, termMeta: 12, tagMeta: 15, media: 2} }); // Test find* functions