jekyll-image-links 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/assets/jekyll-image-links/image_links.js +113 -25
- data/lib/jekyll/image_links/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d2fc33af0a1cda25f029a7a72d68e32eefa8f1fa412fdd4f69281fdb8676a29
|
|
4
|
+
data.tar.gz: 174005c6a08c2f617d953ebe2d874f324c3bfd0107436e93ff23f490bc623606
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6cab285f59d4c32b302686e4995113c2b8ceaba8bbeaf29d9ec2a329ffd2ded5b8de487f6b26f62049c25c9fd155a7d64665d5cd5f807966d6aefae15618670f
|
|
7
|
+
data.tar.gz: 3be18ab75e132c7c7ad4b054879fac3ebb27d72efaedc7b34be916765b049b4c27cc8c45648f3c819ec8bd55fa1df6fe06895adfb380cec51087c14fd74ca526
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
const ROOT_SELECTOR = '[data-jil-root="true"]';
|
|
5
5
|
const config = window.__JIL_CONFIG__ || {};
|
|
6
|
+
// Hosts that already have listeners on this element instance.
|
|
7
|
+
// data-jil-ready is not enough: a hover-popup preview clones the live map,
|
|
8
|
+
// so the attribute is copied, but click listeners are not. A WeakSet tracks
|
|
9
|
+
// the actual element. Clones are absent from it and get set up again, and
|
|
10
|
+
// entries disappear when the preview window is discarded.
|
|
11
|
+
const readyHosts = new WeakSet();
|
|
6
12
|
|
|
7
13
|
function getHoverPopup() {
|
|
8
14
|
const api = window.JekyllHoverPopup;
|
|
@@ -83,7 +89,23 @@
|
|
|
83
89
|
);
|
|
84
90
|
});
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
// Maps already in the page. Maps that appear later, such as inside a
|
|
93
|
+
// preview window, are handled by watchInsertedMaps.
|
|
94
|
+
initWithin(document);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Set up every map host inside root. root may be the document (first load)
|
|
98
|
+
// or a node just inserted into a preview window.
|
|
99
|
+
function initWithin(root) {
|
|
100
|
+
if (!root || !root.querySelectorAll) return;
|
|
101
|
+
|
|
102
|
+
const hosts = [];
|
|
103
|
+
// The inserted node can be the host itself. querySelectorAll only looks
|
|
104
|
+
// at descendants, so include root when it is a map host.
|
|
105
|
+
if (root.nodeType === 1 && root.matches("[data-jil-map]")) hosts.push(root);
|
|
106
|
+
root.querySelectorAll("[data-jil-map]").forEach((host) => hosts.push(host));
|
|
107
|
+
|
|
108
|
+
hosts.forEach((host) => {
|
|
87
109
|
try {
|
|
88
110
|
initMapHost(host);
|
|
89
111
|
} catch (error) {
|
|
@@ -92,9 +114,45 @@
|
|
|
92
114
|
});
|
|
93
115
|
}
|
|
94
116
|
|
|
117
|
+
// Page load only sees maps in the original document. Preview windows fetch
|
|
118
|
+
// or clone section HTML later, so watch for those nodes and set them up then.
|
|
119
|
+
function watchInsertedMaps() {
|
|
120
|
+
if (!document.body || typeof MutationObserver === "undefined") return;
|
|
121
|
+
|
|
122
|
+
const observer = new MutationObserver((mutations) => {
|
|
123
|
+
mutations.forEach((mutation) => {
|
|
124
|
+
mutation.addedNodes.forEach((node) => {
|
|
125
|
+
// Text nodes cannot contain a map host.
|
|
126
|
+
if (node.nodeType !== 1) return;
|
|
127
|
+
initWithin(node);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// subtree covers maps nested inside the preview's section wrapper,
|
|
133
|
+
// not only nodes appended directly to body.
|
|
134
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Drop UI that was copied from an already-initialized map. Labels and the
|
|
138
|
+
// viewer button are created in JS, so a clone includes the elements but not
|
|
139
|
+
// their listeners. Removing them lets init add a fresh, working copy.
|
|
140
|
+
// Server-rendered markup has neither, so this is a no-op on first setup.
|
|
141
|
+
function stripGeneratedUi(host) {
|
|
142
|
+
host.querySelectorAll(".jil-label-layer").forEach((node) => node.remove());
|
|
143
|
+
const figure = host.closest(".jil-figure");
|
|
144
|
+
if (!figure) return;
|
|
145
|
+
// The toolbar is a sibling of the host, inserted after the caption.
|
|
146
|
+
figure.querySelectorAll(":scope > .jil-toolbar").forEach((node) => node.remove());
|
|
147
|
+
}
|
|
148
|
+
|
|
95
149
|
function initMapHost(host) {
|
|
96
|
-
|
|
150
|
+
// Skip hosts already bound in this document. Clones are different elements
|
|
151
|
+
// and fall through even when they carry data-jil-ready from the original.
|
|
152
|
+
if (readyHosts.has(host)) return;
|
|
153
|
+
readyHosts.add(host);
|
|
97
154
|
host.dataset.jilReady = "true";
|
|
155
|
+
stripGeneratedUi(host);
|
|
98
156
|
|
|
99
157
|
let mapData;
|
|
100
158
|
try {
|
|
@@ -120,24 +178,57 @@
|
|
|
120
178
|
if (viewer) addViewerButton(host, mapData);
|
|
121
179
|
}
|
|
122
180
|
|
|
181
|
+
// Keep overlay geometry in sync with the image, including inside a preview
|
|
182
|
+
// that is opened, resized, and then closed.
|
|
183
|
+
function bindLiveUpdates(host, img, update) {
|
|
184
|
+
const onLoad = () => update();
|
|
185
|
+
img.addEventListener("load", onLoad);
|
|
186
|
+
|
|
187
|
+
// Window listeners and a ResizeObserver would keep a closed preview's
|
|
188
|
+
// nodes alive. Drop them once the host has left the document.
|
|
189
|
+
const detach = () => {
|
|
190
|
+
window.removeEventListener("resize", onResize);
|
|
191
|
+
if (observer) observer.disconnect();
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const onResize = () => {
|
|
195
|
+
if (!host.isConnected) {
|
|
196
|
+
detach();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
update();
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
let observer = null;
|
|
203
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
204
|
+
observer = new ResizeObserver(() => {
|
|
205
|
+
// Closing a preview disconnects the host and fires this observer.
|
|
206
|
+
if (!host.isConnected) {
|
|
207
|
+
detach();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
update();
|
|
211
|
+
});
|
|
212
|
+
// Watch both: the host size follows the preview window, and the image
|
|
213
|
+
// size follows its own load and CSS.
|
|
214
|
+
observer.observe(host);
|
|
215
|
+
observer.observe(img);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
window.addEventListener("resize", onResize);
|
|
219
|
+
// A cached image may already be complete, so the load event never fires.
|
|
220
|
+
if (img.complete) update();
|
|
221
|
+
}
|
|
222
|
+
|
|
123
223
|
function bindOverlayGeometry(overlay, host, mapData, img) {
|
|
124
|
-
|
|
224
|
+
bindLiveUpdates(host, img, () => {
|
|
125
225
|
const geom = getMapGeometry(img, mapData);
|
|
126
226
|
if (!geom || !geom.width || !geom.height) return;
|
|
127
227
|
overlay.style.left = `${geom.offsetX}px`;
|
|
128
228
|
overlay.style.top = `${geom.offsetY}px`;
|
|
129
229
|
overlay.style.width = `${geom.width}px`;
|
|
130
230
|
overlay.style.height = `${geom.height}px`;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
if (img.complete) update();
|
|
134
|
-
img.addEventListener("load", update);
|
|
135
|
-
window.addEventListener("resize", update);
|
|
136
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
137
|
-
const observer = new ResizeObserver(update);
|
|
138
|
-
observer.observe(host);
|
|
139
|
-
observer.observe(img);
|
|
140
|
-
}
|
|
231
|
+
});
|
|
141
232
|
}
|
|
142
233
|
|
|
143
234
|
function renderLabels(host, mapData, img) {
|
|
@@ -146,7 +237,7 @@
|
|
|
146
237
|
host.appendChild(overlay);
|
|
147
238
|
bindOverlayGeometry(overlay, host, mapData, img);
|
|
148
239
|
|
|
149
|
-
|
|
240
|
+
bindLiveUpdates(host, img, () => {
|
|
150
241
|
overlay.innerHTML = "";
|
|
151
242
|
const geom = getMapGeometry(img, mapData);
|
|
152
243
|
if (!geom || !geom.width || !geom.height) return;
|
|
@@ -169,16 +260,7 @@
|
|
|
169
260
|
link.title = region.title || label;
|
|
170
261
|
overlay.appendChild(link);
|
|
171
262
|
});
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
if (img.complete) update();
|
|
175
|
-
img.addEventListener("load", update);
|
|
176
|
-
window.addEventListener("resize", update);
|
|
177
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
178
|
-
const observer = new ResizeObserver(update);
|
|
179
|
-
observer.observe(host);
|
|
180
|
-
observer.observe(img);
|
|
181
|
-
}
|
|
263
|
+
});
|
|
182
264
|
}
|
|
183
265
|
|
|
184
266
|
function bindInlineClicks(host, mapData, img) {
|
|
@@ -593,7 +675,13 @@
|
|
|
593
675
|
return;
|
|
594
676
|
}
|
|
595
677
|
|
|
596
|
-
const run = () =>
|
|
678
|
+
const run = () => {
|
|
679
|
+
// Observe before the first pass so a preview inserted during init is
|
|
680
|
+
// not missed. Init itself does not add map hosts, so this does not
|
|
681
|
+
// set the same map up twice.
|
|
682
|
+
watchInsertedMaps();
|
|
683
|
+
init();
|
|
684
|
+
};
|
|
597
685
|
|
|
598
686
|
if (document.querySelector('[data-hover-popup-root="true"]') && !getHoverPopup()) {
|
|
599
687
|
window.setTimeout(run, 0);
|