aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/css/display.css75
-rw-r--r--ext/data/schemas/dictionary-term-bank-v3-schema.json10
-rw-r--r--ext/display-templates.html3
-rw-r--r--ext/js/display/display-generator.js44
-rw-r--r--ext/js/language/dictionary-importer.js7
5 files changed, 87 insertions, 52 deletions
diff --git a/ext/css/display.css b/ext/css/display.css
index d9a2acd2..529e4249 100644
--- a/ext/css/display.css
+++ b/ext/css/display.css
@@ -1571,6 +1571,8 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
.gloss-image-link {
cursor: inherit;
color: inherit;
+ display: inline-block;
+ position: relative;
}
.gloss-image-link[href]:hover {
cursor: pointer;
@@ -1588,7 +1590,7 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
white-space: normal;
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';
display: table-cell;
width: 100%;
@@ -1599,15 +1601,17 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
}
.gloss-image {
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;
left: 0;
top: 0;
width: 100%;
height: 100%;
- vertical-align: top;
- object-fit: contain;
- border: none;
- outline: none;
}
.gloss-image:not([src]) {
display: none;
@@ -1619,13 +1623,15 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
image-rendering: pixelated;
image-rendering: crisp-edges;
}
-.gloss-image-aspect-ratio-sizer {
- content: '';
+.gloss-image-link[data-has-aspect-ratio=true] .gloss-image-aspect-ratio-sizer {
display: inline-block;
width: 0;
vertical-align: top;
font-size: 0;
}
+.gloss-image-link-text {
+ display: none;
+}
.gloss-image-link-text::before {
content: '[';
}
@@ -1633,9 +1639,38 @@ button.definition-item-expansion-button:focus:focus-visible+.definition-item-con
content: ']';
}
.gloss-image-description {
+ display: block;
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-glyph-container {
@@ -2110,32 +2145,6 @@ button.footer-notification-close-button {
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 {
display: none;
}
diff --git a/ext/data/schemas/dictionary-term-bank-v3-schema.json b/ext/data/schemas/dictionary-term-bank-v3-schema.json
index 4790e561..2289dfd6 100644
--- a/ext/data/schemas/dictionary-term-bank-v3-schema.json
+++ b/ext/data/schemas/dictionary-term-bank-v3-schema.json
@@ -104,6 +104,16 @@
"type": "boolean",
"description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.",
"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
}
}
}
diff --git a/ext/display-templates.html b/ext/display-templates.html
index 3262c15a..61d55638 100644
--- a/ext/display-templates.html
+++ b/ext/display-templates.html
@@ -57,7 +57,8 @@
</li></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-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>
<!-- Frequency templates -->
diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js
index eb9c122d..299d730b 100644
--- a/ext/js/display/display-generator.js
+++ b/ext/js/display/display-generator.js
@@ -309,7 +309,26 @@ class DisplayGenerator {
}
_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 = (
typeof preferredWidth === 'number' ?
@@ -327,6 +346,9 @@ class DisplayGenerator {
node.dataset.path = path;
node.dataset.dictionary = dictionary;
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');
imageContainer.style.width = `${usedWidth}em`;
@@ -338,35 +360,29 @@ class DisplayGenerator {
aspectRatioSizer.style.paddingTop = `${aspectRatio * 100.0}%`;
const image = node.querySelector('img.gloss-image');
- const imageLink = node.querySelector('.gloss-image-link');
image.dataset.pixelated = `${pixelated === true}`;
if (this._mediaLoader !== null) {
this._mediaLoader.loadMedia(
path,
dictionary,
- (url) => this._setImageData(node, image, imageLink, url, false),
- () => this._setImageData(node, image, imageLink, null, true)
+ (url) => this._setImageData(node, image, url, false),
+ () => this._setImageData(node, image, null, true)
);
}
- if (typeof description === 'string') {
- const container = node.querySelector('.gloss-image-description');
- this._setMultilineTextContent(container, description);
- }
-
return node;
}
- _setImageData(container, image, imageLink, url, unloaded) {
+ _setImageData(node, image, url, unloaded) {
if (url !== null) {
image.src = url;
- imageLink.href = url;
- container.dataset.imageLoadState = 'loaded';
+ node.href = url;
+ node.dataset.imageLoadState = 'loaded';
} else {
image.removeAttribute('src');
- imageLink.removeAttribute('href');
- container.dataset.imageLoadState = unloaded ? 'unloaded' : 'load-error';
+ node.removeAttribute('href');
+ node.dataset.imageLoadState = unloaded ? 'unloaded' : 'load-error';
}
}
diff --git a/ext/js/language/dictionary-importer.js b/ext/js/language/dictionary-importer.js
index e060b3b1..051375a0 100644
--- a/ext/js/language/dictionary-importer.js
+++ b/ext/js/language/dictionary-importer.js
@@ -306,10 +306,8 @@ class DictionaryImporter {
}
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);
-
- // Create new data
const newData = {
type: 'image',
path,
@@ -321,7 +319,8 @@ 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 collapsed === 'boolean') { newData.collapsed = collapsed; }
+ if (typeof collapsible === 'boolean') { newData.collapsible = collapsible; }
return newData;
}