Dictionary image display refactoring (#1687)
* Generalize image definition generation * Enable optional aspect ratio * Move styles * Update styles * Add more options for collapsing images * Add image options for collapsing * Improve layout for images that are collapsed
This commit is contained in:
parent
76276e78da
commit
f3cf4d10c7
@ -1571,6 +1571,8 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
|
|||||||
.gloss-image-link {
|
.gloss-image-link {
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.gloss-image-link[href]:hover {
|
.gloss-image-link[href]:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -1588,7 +1590,7 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
color: var(--text-color-light3);
|
color: var(--text-color-light3);
|
||||||
}
|
}
|
||||||
.gloss-item[data-has-image=true][data-image-load-state=load-error] .gloss-image-container-overlay::after {
|
.gloss-image-link[data-has-image=true][data-image-load-state=load-error] .gloss-image-container-overlay::after {
|
||||||
content: 'Image failed to load';
|
content: 'Image failed to load';
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -1599,15 +1601,17 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
|
|||||||
}
|
}
|
||||||
.gloss-image {
|
.gloss-image {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
object-fit: contain;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.gloss-image-link[data-has-aspect-ratio=true] .gloss-image {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
vertical-align: top;
|
|
||||||
object-fit: contain;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
}
|
}
|
||||||
.gloss-image:not([src]) {
|
.gloss-image:not([src]) {
|
||||||
display: none;
|
display: none;
|
||||||
@ -1619,13 +1623,15 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
|
|||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
image-rendering: crisp-edges;
|
image-rendering: crisp-edges;
|
||||||
}
|
}
|
||||||
.gloss-image-aspect-ratio-sizer {
|
.gloss-image-link[data-has-aspect-ratio=true] .gloss-image-aspect-ratio-sizer {
|
||||||
content: '';
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 0;
|
width: 0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
}
|
}
|
||||||
|
.gloss-image-link-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.gloss-image-link-text::before {
|
.gloss-image-link-text::before {
|
||||||
content: '[';
|
content: '[';
|
||||||
}
|
}
|
||||||
@ -1633,9 +1639,38 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
|
|||||||
content: ']';
|
content: ']';
|
||||||
}
|
}
|
||||||
.gloss-image-description {
|
.gloss-image-description {
|
||||||
|
display: block;
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gloss-image-link[data-collapsed=true] .gloss-image-container,
|
||||||
|
:root[data-glossary-layout-mode=compact] .gloss-image-link[data-collapsible=true] .gloss-image-container {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-link[data-collapsed=true] .gloss-image-container,
|
||||||
|
:root[data-glossary-layout-mode=compact] .entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-link[data-collapsible=true] .gloss-image-container {
|
||||||
|
bottom: 100%;
|
||||||
|
top: auto;
|
||||||
|
}
|
||||||
|
.gloss-image-link[data-collapsed=true]:hover .gloss-image-container,
|
||||||
|
.gloss-image-link[data-collapsed=true]:focus .gloss-image-container,
|
||||||
|
:root[data-glossary-layout-mode=compact] .gloss-image-link[data-collapsible=true]:hover .gloss-image-container,
|
||||||
|
:root[data-glossary-layout-mode=compact] .gloss-image-link[data-collapsible=true]:focus .gloss-image-container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.gloss-image-link[data-collapsed=true] .gloss-image-link-text,
|
||||||
|
:root[data-glossary-layout-mode=compact] .gloss-image-link[data-collapsible=true] .gloss-image-link-text {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.gloss-image-link[data-collapsed=true]~.gloss-image-description,
|
||||||
|
:root[data-glossary-layout-mode=compact] .gloss-image-description {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Kanji */
|
/* Kanji */
|
||||||
.kanji-glyph-container {
|
.kanji-glyph-container {
|
||||||
@ -2110,32 +2145,6 @@ button.footer-notification-close-button {
|
|||||||
color: var(--text-color-light3);
|
color: var(--text-color-light3);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-glossary-layout-mode=compact] .gloss-image-container {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 100%;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
:root[data-glossary-layout-mode=compact] .entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-container {
|
|
||||||
bottom: 100%;
|
|
||||||
top: auto;
|
|
||||||
}
|
|
||||||
:root[data-glossary-layout-mode=compact] .gloss-image-link {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
:root[data-glossary-layout-mode=compact] .gloss-image-link:hover .gloss-image-container,
|
|
||||||
:root[data-glossary-layout-mode=compact] .gloss-image-link:focus .gloss-image-container {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
:root:not([data-glossary-layout-mode=compact]) .gloss-image-link-text {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
:root:not([data-glossary-layout-mode=compact]) .gloss-image-description {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root[data-popup-display-mode=full-width] .frame-resizer-container {
|
:root[data-popup-display-mode=full-width] .frame-resizer-container {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,16 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.",
|
"description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"collapsed": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether or not the image is collapsed by default.",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"collapsible": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether or not the image can be collapsed.",
|
||||||
|
"default": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,8 @@
|
|||||||
</li></template>
|
</li></template>
|
||||||
<template id="definition-disambiguation-template"><span class="definition-disambiguation"></span></template>
|
<template id="definition-disambiguation-template"><span class="definition-disambiguation"></span></template>
|
||||||
<template id="gloss-item-template"><li class="gloss-item click-scannable"><span class="gloss-separator"> </span><span class="gloss-content"></span></li></template>
|
<template id="gloss-item-template"><li class="gloss-item click-scannable"><span class="gloss-separator"> </span><span class="gloss-content"></span></li></template>
|
||||||
<template id="gloss-item-image-template"><li class="gloss-item click-scannable" data-has-image="true"><span class="gloss-separator"> </span><span class="gloss-content"><a class="gloss-image-link" target="_blank" rel="noreferrer noopener"><span class="gloss-image-container"><span class="gloss-image-aspect-ratio-sizer"></span><img class="gloss-image" alt=""><span class="gloss-image-container-overlay"></span></span><span class="gloss-image-link-text">Image</span></a> <span class="gloss-image-description"></span></span></li></template>
|
<template id="gloss-item-image-template"><a class="gloss-image-link" target="_blank" rel="noreferrer noopener"><span class="gloss-image-container"><span class="gloss-image-aspect-ratio-sizer"></span><img class="gloss-image" alt=""><span class="gloss-image-container-overlay"></span></span><span class="gloss-image-link-text">Image</span></a></template>
|
||||||
|
<template id="gloss-item-image-description-template"> <span class="gloss-image-description"></span></template>
|
||||||
<template id="inflection-template"><span class="inflection"></span><span class="inflection-separator"> </span></template>
|
<template id="inflection-template"><span class="inflection"></span><span class="inflection-separator"> </span></template>
|
||||||
|
|
||||||
<!-- Frequency templates -->
|
<!-- Frequency templates -->
|
||||||
|
@ -309,7 +309,26 @@ class DisplayGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_createTermDefinitionEntryImage(data, dictionary) {
|
_createTermDefinitionEntryImage(data, dictionary) {
|
||||||
const {path, width, height, preferredWidth, preferredHeight, title, description, pixelated} = data;
|
const {description} = data;
|
||||||
|
|
||||||
|
const node = this._templates.instantiate('gloss-item');
|
||||||
|
|
||||||
|
const contentContainer = node.querySelector('.gloss-content');
|
||||||
|
const image = this._createDefinitionImage(data, dictionary);
|
||||||
|
contentContainer.appendChild(image);
|
||||||
|
|
||||||
|
if (typeof description === 'string') {
|
||||||
|
const fragment = this._templates.instantiateFragment('gloss-item-image-description');
|
||||||
|
const container = fragment.querySelector('.gloss-image-description');
|
||||||
|
this._setMultilineTextContent(container, description);
|
||||||
|
contentContainer.appendChild(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createDefinitionImage(data, dictionary) {
|
||||||
|
const {path, width, height, preferredWidth, preferredHeight, title, pixelated, collapsed, collapsible} = data;
|
||||||
|
|
||||||
const usedWidth = (
|
const usedWidth = (
|
||||||
typeof preferredWidth === 'number' ?
|
typeof preferredWidth === 'number' ?
|
||||||
@ -327,6 +346,9 @@ class DisplayGenerator {
|
|||||||
node.dataset.path = path;
|
node.dataset.path = path;
|
||||||
node.dataset.dictionary = dictionary;
|
node.dataset.dictionary = dictionary;
|
||||||
node.dataset.imageLoadState = 'not-loaded';
|
node.dataset.imageLoadState = 'not-loaded';
|
||||||
|
node.dataset.hasAspectRatio = 'true';
|
||||||
|
node.dataset.collapsed = typeof collapsed === 'boolean' ? `${collapsed}` : 'false';
|
||||||
|
node.dataset.collapsible = typeof collapsible === 'boolean' ? `${collapsible}` : 'true';
|
||||||
|
|
||||||
const imageContainer = node.querySelector('.gloss-image-container');
|
const imageContainer = node.querySelector('.gloss-image-container');
|
||||||
imageContainer.style.width = `${usedWidth}em`;
|
imageContainer.style.width = `${usedWidth}em`;
|
||||||
@ -338,35 +360,29 @@ class DisplayGenerator {
|
|||||||
aspectRatioSizer.style.paddingTop = `${aspectRatio * 100.0}%`;
|
aspectRatioSizer.style.paddingTop = `${aspectRatio * 100.0}%`;
|
||||||
|
|
||||||
const image = node.querySelector('img.gloss-image');
|
const image = node.querySelector('img.gloss-image');
|
||||||
const imageLink = node.querySelector('.gloss-image-link');
|
|
||||||
image.dataset.pixelated = `${pixelated === true}`;
|
image.dataset.pixelated = `${pixelated === true}`;
|
||||||
|
|
||||||
if (this._mediaLoader !== null) {
|
if (this._mediaLoader !== null) {
|
||||||
this._mediaLoader.loadMedia(
|
this._mediaLoader.loadMedia(
|
||||||
path,
|
path,
|
||||||
dictionary,
|
dictionary,
|
||||||
(url) => this._setImageData(node, image, imageLink, url, false),
|
(url) => this._setImageData(node, image, url, false),
|
||||||
() => this._setImageData(node, image, imageLink, null, true)
|
() => this._setImageData(node, image, null, true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof description === 'string') {
|
|
||||||
const container = node.querySelector('.gloss-image-description');
|
|
||||||
this._setMultilineTextContent(container, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setImageData(container, image, imageLink, url, unloaded) {
|
_setImageData(node, image, url, unloaded) {
|
||||||
if (url !== null) {
|
if (url !== null) {
|
||||||
image.src = url;
|
image.src = url;
|
||||||
imageLink.href = url;
|
node.href = url;
|
||||||
container.dataset.imageLoadState = 'loaded';
|
node.dataset.imageLoadState = 'loaded';
|
||||||
} else {
|
} else {
|
||||||
image.removeAttribute('src');
|
image.removeAttribute('src');
|
||||||
imageLink.removeAttribute('href');
|
node.removeAttribute('href');
|
||||||
container.dataset.imageLoadState = unloaded ? 'unloaded' : 'load-error';
|
node.dataset.imageLoadState = unloaded ? 'unloaded' : 'load-error';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,10 +306,8 @@ class DictionaryImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _formatDictionaryTermGlossaryImage(data, context, entry) {
|
async _formatDictionaryTermGlossaryImage(data, context, entry) {
|
||||||
const {path, width: preferredWidth, height: preferredHeight, title, description, pixelated} = data;
|
const {path, width: preferredWidth, height: preferredHeight, title, description, pixelated, collapsed, collapsible} = data;
|
||||||
const {width, height} = await this._getImageMedia(path, context, entry);
|
const {width, height} = await this._getImageMedia(path, context, entry);
|
||||||
|
|
||||||
// Create new data
|
|
||||||
const newData = {
|
const newData = {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
path,
|
path,
|
||||||
@ -321,7 +319,8 @@ class DictionaryImporter {
|
|||||||
if (typeof title === 'string') { newData.title = title; }
|
if (typeof title === 'string') { newData.title = title; }
|
||||||
if (typeof description === 'string') { newData.description = description; }
|
if (typeof description === 'string') { newData.description = description; }
|
||||||
if (typeof pixelated === 'boolean') { newData.pixelated = pixelated; }
|
if (typeof pixelated === 'boolean') { newData.pixelated = pixelated; }
|
||||||
|
if (typeof collapsed === 'boolean') { newData.collapsed = collapsed; }
|
||||||
|
if (typeof collapsible === 'boolean') { newData.collapsible = collapsible; }
|
||||||
return newData;
|
return newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user