PluginProbe
Gutenberg / 22.4.3
Gutenberg v22.4.3
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / build / modules / block-library / image / view.js

view.js in Gutenberg 22.4.3, at build/modules/block-library/image/view.js

343 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // packages/block-library/build-module/image/view.mjs
2 import {
3 store,
4 getContext,
5 getElement,
6 withSyncEvent,
7 withScope
8 } from "@wordpress/interactivity";
9
10 // packages/block-library/build-module/image/constants.mjs
11 var IMAGE_PRELOAD_DELAY = 200;
12
13 // packages/block-library/build-module/image/view.mjs
14 var isTouching = false;
15 var lastTouchTime = 0;
16 function getImageSrc({ uploadedSrc }) {
17 return uploadedSrc || "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
18 }
19 function getImageSrcset({ lightboxSrcset }) {
20 return lightboxSrcset || "";
21 }
22 var { state, actions, callbacks } = store(
23 "core/image",
24 {
25 state: {
26 currentImageId: null,
27 preloadTimers: /* @__PURE__ */ new Map(),
28 preloadedImageIds: /* @__PURE__ */ new Set(),
29 get currentImage() {
30 return state.metadata[state.currentImageId];
31 },
32 get overlayOpened() {
33 return state.currentImageId !== null;
34 },
35 get roleAttribute() {
36 return state.overlayOpened ? "dialog" : null;
37 },
38 get ariaModal() {
39 return state.overlayOpened ? "true" : null;
40 },
41 get enlargedSrc() {
42 return getImageSrc(state.currentImage);
43 },
44 get enlargedSrcset() {
45 return getImageSrcset(state.currentImage);
46 },
47 get figureStyles() {
48 return state.overlayOpened && `${state.currentImage.figureStyles?.replace(
49 /margin[^;]*;?/g,
50 ""
51 )};`;
52 },
53 get imgStyles() {
54 return state.overlayOpened && `${state.currentImage.imgStyles?.replace(
55 /;$/,
56 ""
57 )}; object-fit:cover;`;
58 },
59 get imageButtonRight() {
60 const { imageId } = getContext();
61 return state.metadata[imageId].imageButtonRight;
62 },
63 get imageButtonTop() {
64 const { imageId } = getContext();
65 return state.metadata[imageId].imageButtonTop;
66 },
67 get isContentHidden() {
68 const ctx = getContext();
69 return state.overlayEnabled && state.currentImageId === ctx.imageId;
70 },
71 get isContentVisible() {
72 const ctx = getContext();
73 return !state.overlayEnabled && state.currentImageId === ctx.imageId;
74 }
75 },
76 actions: {
77 showLightbox() {
78 const { imageId } = getContext();
79 if (!state.metadata[imageId].imageRef?.complete) {
80 return;
81 }
82 state.scrollTopReset = document.documentElement.scrollTop;
83 state.scrollLeftReset = document.documentElement.scrollLeft;
84 state.overlayEnabled = true;
85 state.currentImageId = imageId;
86 callbacks.setOverlayStyles();
87 },
88 hideLightbox() {
89 if (state.overlayEnabled) {
90 state.overlayEnabled = false;
91 setTimeout(function() {
92 state.currentImage.buttonRef.focus({
93 preventScroll: true
94 });
95 state.currentImageId = null;
96 }, 450);
97 }
98 },
99 handleKeydown: withSyncEvent((event) => {
100 if (state.overlayEnabled) {
101 if (event.key === "Tab") {
102 event.preventDefault();
103 const { ref } = getElement();
104 ref.querySelector("button").focus();
105 }
106 if (event.key === "Escape") {
107 actions.hideLightbox();
108 }
109 }
110 }),
111 handleTouchMove: withSyncEvent((event) => {
112 if (state.overlayEnabled) {
113 event.preventDefault();
114 }
115 }),
116 handleTouchStart() {
117 isTouching = true;
118 },
119 handleTouchEnd() {
120 lastTouchTime = Date.now();
121 isTouching = false;
122 },
123 handleScroll() {
124 if (state.overlayOpened) {
125 if (!isTouching && Date.now() - lastTouchTime > 450) {
126 window.scrollTo(
127 state.scrollLeftReset,
128 state.scrollTopReset
129 );
130 }
131 }
132 },
133 preloadImage() {
134 const { imageId } = getContext();
135 if (state.preloadedImageIds.has(imageId)) {
136 return;
137 }
138 const imageMetadata = state.metadata[imageId];
139 const imageLink = document.createElement("link");
140 imageLink.rel = "preload";
141 imageLink.as = "image";
142 imageLink.href = getImageSrc(imageMetadata);
143 const srcset = getImageSrcset(imageMetadata);
144 if (srcset) {
145 imageLink.setAttribute("imagesrcset", srcset);
146 imageLink.setAttribute("imagesizes", "100vw");
147 }
148 document.head.appendChild(imageLink);
149 state.preloadedImageIds.add(imageId);
150 },
151 preloadImageWithDelay() {
152 const { imageId } = getContext();
153 actions.cancelPreload();
154 const timerId = setTimeout(
155 withScope(() => {
156 actions.preloadImage();
157 state.preloadTimers.delete(imageId);
158 }),
159 IMAGE_PRELOAD_DELAY
160 );
161 state.preloadTimers.set(imageId, timerId);
162 },
163 cancelPreload() {
164 const { imageId } = getContext();
165 if (state.preloadTimers.has(imageId)) {
166 clearTimeout(state.preloadTimers.get(imageId));
167 state.preloadTimers.delete(imageId);
168 }
169 }
170 },
171 callbacks: {
172 setOverlayStyles() {
173 if (!state.overlayEnabled) {
174 return;
175 }
176 let {
177 naturalWidth,
178 naturalHeight,
179 offsetWidth: originalWidth,
180 offsetHeight: originalHeight
181 } = state.currentImage.imageRef;
182 let { x: screenPosX, y: screenPosY } = state.currentImage.imageRef.getBoundingClientRect();
183 const naturalRatio = naturalWidth / naturalHeight;
184 let originalRatio = originalWidth / originalHeight;
185 if (state.currentImage.scaleAttr === "contain") {
186 if (naturalRatio > originalRatio) {
187 const heightWithoutSpace = originalWidth / naturalRatio;
188 screenPosY += (originalHeight - heightWithoutSpace) / 2;
189 originalHeight = heightWithoutSpace;
190 } else {
191 const widthWithoutSpace = originalHeight * naturalRatio;
192 screenPosX += (originalWidth - widthWithoutSpace) / 2;
193 originalWidth = widthWithoutSpace;
194 }
195 }
196 originalRatio = originalWidth / originalHeight;
197 let imgMaxWidth = parseFloat(
198 state.currentImage.targetWidth !== "none" ? state.currentImage.targetWidth : naturalWidth
199 );
200 let imgMaxHeight = parseFloat(
201 state.currentImage.targetHeight !== "none" ? state.currentImage.targetHeight : naturalHeight
202 );
203 let imgRatio = imgMaxWidth / imgMaxHeight;
204 let containerMaxWidth = imgMaxWidth;
205 let containerMaxHeight = imgMaxHeight;
206 let containerWidth = imgMaxWidth;
207 let containerHeight = imgMaxHeight;
208 if (naturalRatio.toFixed(2) !== imgRatio.toFixed(2)) {
209 if (naturalRatio > imgRatio) {
210 const reducedHeight = imgMaxWidth / naturalRatio;
211 if (imgMaxHeight - reducedHeight > imgMaxWidth) {
212 imgMaxHeight = reducedHeight;
213 imgMaxWidth = reducedHeight * naturalRatio;
214 } else {
215 imgMaxHeight = imgMaxWidth / naturalRatio;
216 }
217 } else {
218 const reducedWidth = imgMaxHeight * naturalRatio;
219 if (imgMaxWidth - reducedWidth > imgMaxHeight) {
220 imgMaxWidth = reducedWidth;
221 imgMaxHeight = reducedWidth / naturalRatio;
222 } else {
223 imgMaxWidth = imgMaxHeight * naturalRatio;
224 }
225 }
226 containerWidth = imgMaxWidth;
227 containerHeight = imgMaxHeight;
228 imgRatio = imgMaxWidth / imgMaxHeight;
229 if (originalRatio > imgRatio) {
230 containerMaxWidth = imgMaxWidth;
231 containerMaxHeight = containerMaxWidth / originalRatio;
232 } else {
233 containerMaxHeight = imgMaxHeight;
234 containerMaxWidth = containerMaxHeight * originalRatio;
235 }
236 }
237 if (originalWidth > containerWidth || originalHeight > containerHeight) {
238 containerWidth = originalWidth;
239 containerHeight = originalHeight;
240 }
241 let horizontalPadding = 0;
242 if (window.innerWidth > 480) {
243 horizontalPadding = 80;
244 } else if (window.innerWidth > 1920) {
245 horizontalPadding = 160;
246 }
247 const verticalPadding = 80;
248 const targetMaxWidth = Math.min(
249 window.innerWidth - horizontalPadding,
250 containerWidth
251 );
252 const targetMaxHeight = Math.min(
253 window.innerHeight - verticalPadding,
254 containerHeight
255 );
256 const targetContainerRatio = targetMaxWidth / targetMaxHeight;
257 if (originalRatio > targetContainerRatio) {
258 containerWidth = targetMaxWidth;
259 containerHeight = containerWidth / originalRatio;
260 } else {
261 containerHeight = targetMaxHeight;
262 containerWidth = containerHeight * originalRatio;
263 }
264 const containerScale = originalWidth / containerWidth;
265 const lightboxImgWidth = imgMaxWidth * (containerWidth / containerMaxWidth);
266 const lightboxImgHeight = imgMaxHeight * (containerHeight / containerMaxHeight);
267 state.overlayStyles = `
268 --wp--lightbox-initial-top-position: ${screenPosY}px;
269 --wp--lightbox-initial-left-position: ${screenPosX}px;
270 --wp--lightbox-container-width: ${containerWidth + 1}px;
271 --wp--lightbox-container-height: ${containerHeight + 1}px;
272 --wp--lightbox-image-width: ${lightboxImgWidth}px;
273 --wp--lightbox-image-height: ${lightboxImgHeight}px;
274 --wp--lightbox-scale: ${containerScale};
275 --wp--lightbox-scrollbar-width: ${window.innerWidth - document.documentElement.clientWidth}px;
276 `;
277 },
278 setButtonStyles() {
279 const { ref } = getElement();
280 if (!ref) {
281 return;
282 }
283 const { imageId } = getContext();
284 state.metadata[imageId].imageRef = ref;
285 state.metadata[imageId].currentSrc = ref.currentSrc;
286 const {
287 naturalWidth,
288 naturalHeight,
289 offsetWidth,
290 offsetHeight
291 } = ref;
292 if (naturalWidth === 0 || naturalHeight === 0) {
293 return;
294 }
295 const figure = ref.parentElement;
296 const figureWidth = ref.parentElement.clientWidth;
297 let figureHeight = ref.parentElement.clientHeight;
298 const caption = figure.querySelector("figcaption");
299 if (caption) {
300 const captionComputedStyle = window.getComputedStyle(caption);
301 if (!["absolute", "fixed"].includes(
302 captionComputedStyle.position
303 )) {
304 figureHeight = figureHeight - caption.offsetHeight - parseFloat(captionComputedStyle.marginTop) - parseFloat(captionComputedStyle.marginBottom);
305 }
306 }
307 const buttonOffsetTop = figureHeight - offsetHeight;
308 const buttonOffsetRight = figureWidth - offsetWidth;
309 let imageButtonTop = buttonOffsetTop + 16;
310 let imageButtonRight = buttonOffsetRight + 16;
311 if (state.metadata[imageId].scaleAttr === "contain") {
312 const naturalRatio = naturalWidth / naturalHeight;
313 const offsetRatio = offsetWidth / offsetHeight;
314 if (naturalRatio >= offsetRatio) {
315 const referenceHeight = offsetWidth / naturalRatio;
316 imageButtonTop = (offsetHeight - referenceHeight) / 2 + buttonOffsetTop + 16;
317 imageButtonRight = buttonOffsetRight + 16;
318 } else {
319 const referenceWidth = offsetHeight * naturalRatio;
320 imageButtonTop = buttonOffsetTop + 16;
321 imageButtonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16;
322 }
323 }
324 state.metadata[imageId].imageButtonTop = imageButtonTop;
325 state.metadata[imageId].imageButtonRight = imageButtonRight;
326 },
327 setOverlayFocus() {
328 if (state.overlayEnabled) {
329 const { ref } = getElement();
330 ref.focus();
331 }
332 },
333 initTriggerButton() {
334 const { imageId } = getContext();
335 const { ref } = getElement();
336 state.metadata[imageId].buttonRef = ref;
337 }
338 }
339 },
340 { lock: true }
341 );
342 //# sourceMappingURL=view.js.map
343