[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 import * as __WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__ from "@wordpress/interactivity"; 2 /******/ // The require scope 3 /******/ var __webpack_require__ = {}; 4 /******/ 5 /************************************************************************/ 6 /******/ /* webpack/runtime/define property getters */ 7 /******/ (() => { 8 /******/ // define getter functions for harmony exports 9 /******/ __webpack_require__.d = (exports, definition) => { 10 /******/ for(var key in definition) { 11 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 12 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 13 /******/ } 14 /******/ } 15 /******/ }; 16 /******/ })(); 17 /******/ 18 /******/ /* webpack/runtime/hasOwnProperty shorthand */ 19 /******/ (() => { 20 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 21 /******/ })(); 22 /******/ 23 /************************************************************************/ 24 var __webpack_exports__ = {}; 25 26 ;// CONCATENATED MODULE: external "@wordpress/interactivity" 27 var x = (y) => { 28 var x = {}; __webpack_require__.d(x, y); return x 29 } 30 var y = (x) => (() => (x)) 31 const interactivity_namespaceObject = x({ ["getContext"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.getContext), ["getElement"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.getElement), ["store"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.store) }); 32 ;// CONCATENATED MODULE: ./node_modules/@wordpress/block-library/build-module/image/view.js 33 /** 34 * WordPress dependencies 35 */ 36 37 38 /** 39 * Tracks whether user is touching screen; used to differentiate behavior for 40 * touch and mouse input. 41 * 42 * @type {boolean} 43 */ 44 let isTouching = false; 45 46 /** 47 * Tracks the last time the screen was touched; used to differentiate behavior 48 * for touch and mouse input. 49 * 50 * @type {number} 51 */ 52 let lastTouchTime = 0; 53 const { 54 state, 55 actions, 56 callbacks 57 } = (0,interactivity_namespaceObject.store)('core/image', { 58 state: { 59 currentImageId: null, 60 get currentImage() { 61 return state.metadata[state.currentImageId]; 62 }, 63 get overlayOpened() { 64 return state.currentImageId !== null; 65 }, 66 get roleAttribute() { 67 return state.overlayOpened ? 'dialog' : null; 68 }, 69 get ariaModal() { 70 return state.overlayOpened ? 'true' : null; 71 }, 72 get enlargedSrc() { 73 return state.currentImage.uploadedSrc || 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; 74 }, 75 get figureStyles() { 76 return state.overlayOpened && `$state.currentImage.figureStyles?.replace(/margin[^;]*;?/g, '')};`; 77 }, 78 get imgStyles() { 79 return state.overlayOpened && `$state.currentImage.imgStyles?.replace(/;$/, '')}; object-fit:cover;`; 80 }, 81 get imageButtonRight() { 82 const { 83 imageId 84 } = (0,interactivity_namespaceObject.getContext)(); 85 return state.metadata[imageId].imageButtonRight; 86 }, 87 get imageButtonTop() { 88 const { 89 imageId 90 } = (0,interactivity_namespaceObject.getContext)(); 91 return state.metadata[imageId].imageButtonTop; 92 }, 93 get isContentHidden() { 94 const ctx = (0,interactivity_namespaceObject.getContext)(); 95 return state.overlayEnabled && state.currentImageId === ctx.imageId; 96 }, 97 get isContentVisible() { 98 const ctx = (0,interactivity_namespaceObject.getContext)(); 99 return !state.overlayEnabled && state.currentImageId === ctx.imageId; 100 } 101 }, 102 actions: { 103 showLightbox() { 104 const { 105 imageId 106 } = (0,interactivity_namespaceObject.getContext)(); 107 108 // Bails out if the image has not loaded yet. 109 if (!state.metadata[imageId].imageRef?.complete) { 110 return; 111 } 112 113 // Stores the positions of the scroll to fix it until the overlay is 114 // closed. 115 state.scrollTopReset = document.documentElement.scrollTop; 116 state.scrollLeftReset = document.documentElement.scrollLeft; 117 118 // Sets the current expanded image in the state and enables the overlay. 119 state.overlayEnabled = true; 120 state.currentImageId = imageId; 121 122 // Computes the styles of the overlay for the animation. 123 callbacks.setOverlayStyles(); 124 }, 125 hideLightbox() { 126 if (state.overlayEnabled) { 127 // Starts the overlay closing animation. The showClosingAnimation 128 // class is used to avoid showing it on page load. 129 state.showClosingAnimation = true; 130 state.overlayEnabled = false; 131 132 // Waits until the close animation has completed before allowing a 133 // user to scroll again. The duration of this animation is defined in 134 // the `styles.scss` file, but in any case we should wait a few 135 // milliseconds longer than the duration, otherwise a user may scroll 136 // too soon and cause the animation to look sloppy. 137 setTimeout(function () { 138 // Delays before changing the focus. Otherwise the focus ring will 139 // appear on Firefox before the image has finished animating, which 140 // looks broken. 141 state.currentImage.buttonRef.focus({ 142 preventScroll: true 143 }); 144 145 // Resets the current image id to mark the overlay as closed. 146 state.currentImageId = null; 147 }, 450); 148 } 149 }, 150 handleKeydown(event) { 151 if (state.overlayEnabled) { 152 // Focuses the close button when the user presses the tab key. 153 if (event.key === 'Tab') { 154 event.preventDefault(); 155 const { 156 ref 157 } = (0,interactivity_namespaceObject.getElement)(); 158 ref.querySelector('button').focus(); 159 } 160 // Closes the lightbox when the user presses the escape key. 161 if (event.key === 'Escape') { 162 actions.hideLightbox(); 163 } 164 } 165 }, 166 handleTouchMove(event) { 167 // On mobile devices, prevents triggering the scroll event because 168 // otherwise the page jumps around when it resets the scroll position. 169 // This also means that closing the lightbox requires that a user 170 // perform a simple tap. This may be changed in the future if there is a 171 // better alternative to override or reset the scroll position during 172 // swipe actions. 173 if (state.overlayEnabled) { 174 event.preventDefault(); 175 } 176 }, 177 handleTouchStart() { 178 isTouching = true; 179 }, 180 handleTouchEnd() { 181 // Waits a few milliseconds before resetting to ensure that pinch to 182 // zoom works consistently on mobile devices when the lightbox is open. 183 lastTouchTime = Date.now(); 184 isTouching = false; 185 }, 186 handleScroll() { 187 // Prevents scrolling behaviors that trigger content shift while the 188 // lightbox is open. It would be better to accomplish through CSS alone, 189 // but using overflow: hidden is currently the only way to do so and 190 // that causes a layout to shift and prevents the zoom animation from 191 // working in some cases because it's not possible to account for the 192 // layout shift when doing the animation calculations. Instead, it uses 193 // JavaScript to prevent and reset the scrolling behavior. 194 if (state.overlayOpened) { 195 // Avoids overriding the scroll behavior on mobile devices because 196 // doing so breaks the pinch to zoom functionality, and users should 197 // be able to zoom in further on the high-res image. 198 if (!isTouching && Date.now() - lastTouchTime > 450) { 199 // It doesn't rely on `event.preventDefault()` to prevent scrolling 200 // because the scroll event can't be canceled, so it resets the 201 // position instead. 202 window.scrollTo(state.scrollLeftReset, state.scrollTopReset); 203 } 204 } 205 } 206 }, 207 callbacks: { 208 setOverlayStyles() { 209 if (!state.overlayEnabled) { 210 return; 211 } 212 let { 213 naturalWidth, 214 naturalHeight, 215 offsetWidth: originalWidth, 216 offsetHeight: originalHeight 217 } = state.currentImage.imageRef; 218 let { 219 x: screenPosX, 220 y: screenPosY 221 } = state.currentImage.imageRef.getBoundingClientRect(); 222 223 // Natural ratio of the image clicked to open the lightbox. 224 const naturalRatio = naturalWidth / naturalHeight; 225 // Original ratio of the image clicked to open the lightbox. 226 let originalRatio = originalWidth / originalHeight; 227 228 // If it has object-fit: contain, recalculates the original sizes 229 // and the screen position without the blank spaces. 230 if (state.currentImage.scaleAttr === 'contain') { 231 if (naturalRatio > originalRatio) { 232 const heightWithoutSpace = originalWidth / naturalRatio; 233 // Recalculates screen position without the top space. 234 screenPosY += (originalHeight - heightWithoutSpace) / 2; 235 originalHeight = heightWithoutSpace; 236 } else { 237 const widthWithoutSpace = originalHeight * naturalRatio; 238 // Recalculates screen position without the left space. 239 screenPosX += (originalWidth - widthWithoutSpace) / 2; 240 originalWidth = widthWithoutSpace; 241 } 242 } 243 originalRatio = originalWidth / originalHeight; 244 245 // Typically, it uses the image's full-sized dimensions. If those 246 // dimensions have not been set (i.e. an external image with only one 247 // size), the image's dimensions in the lightbox are the same 248 // as those of the image in the content. 249 let imgMaxWidth = parseFloat(state.currentImage.targetWidth !== 'none' ? state.currentImage.targetWidth : naturalWidth); 250 let imgMaxHeight = parseFloat(state.currentImage.targetHeight !== 'none' ? state.currentImage.targetHeight : naturalHeight); 251 252 // Ratio of the biggest image stored in the database. 253 let imgRatio = imgMaxWidth / imgMaxHeight; 254 let containerMaxWidth = imgMaxWidth; 255 let containerMaxHeight = imgMaxHeight; 256 let containerWidth = imgMaxWidth; 257 let containerHeight = imgMaxHeight; 258 259 // Checks if the target image has a different ratio than the original 260 // one (thumbnail). Recalculates the width and height. 261 if (naturalRatio.toFixed(2) !== imgRatio.toFixed(2)) { 262 if (naturalRatio > imgRatio) { 263 // If the width is reached before the height, it keeps the maxWidth 264 // and recalculates the height unless the difference between the 265 // maxHeight and the reducedHeight is higher than the maxWidth, 266 // where it keeps the reducedHeight and recalculate the width. 267 const reducedHeight = imgMaxWidth / naturalRatio; 268 if (imgMaxHeight - reducedHeight > imgMaxWidth) { 269 imgMaxHeight = reducedHeight; 270 imgMaxWidth = reducedHeight * naturalRatio; 271 } else { 272 imgMaxHeight = imgMaxWidth / naturalRatio; 273 } 274 } else { 275 // If the height is reached before the width, it keeps the maxHeight 276 // and recalculate the width unlesss the difference between the 277 // maxWidth and the reducedWidth is higher than the maxHeight, where 278 // it keeps the reducedWidth and recalculate the height. 279 const reducedWidth = imgMaxHeight * naturalRatio; 280 if (imgMaxWidth - reducedWidth > imgMaxHeight) { 281 imgMaxWidth = reducedWidth; 282 imgMaxHeight = reducedWidth / naturalRatio; 283 } else { 284 imgMaxWidth = imgMaxHeight * naturalRatio; 285 } 286 } 287 containerWidth = imgMaxWidth; 288 containerHeight = imgMaxHeight; 289 imgRatio = imgMaxWidth / imgMaxHeight; 290 291 // Calculates the max size of the container. 292 if (originalRatio > imgRatio) { 293 containerMaxWidth = imgMaxWidth; 294 containerMaxHeight = containerMaxWidth / originalRatio; 295 } else { 296 containerMaxHeight = imgMaxHeight; 297 containerMaxWidth = containerMaxHeight * originalRatio; 298 } 299 } 300 301 // If the image has been pixelated on purpose, it keeps that size. 302 if (originalWidth > containerWidth || originalHeight > containerHeight) { 303 containerWidth = originalWidth; 304 containerHeight = originalHeight; 305 } 306 307 // Calculates the final lightbox image size and the scale factor. 308 // MaxWidth is either the window container (accounting for padding) or 309 // the image resolution. 310 let horizontalPadding = 0; 311 if (window.innerWidth > 480) { 312 horizontalPadding = 80; 313 } else if (window.innerWidth > 1920) { 314 horizontalPadding = 160; 315 } 316 const verticalPadding = 80; 317 const targetMaxWidth = Math.min(window.innerWidth - horizontalPadding, containerWidth); 318 const targetMaxHeight = Math.min(window.innerHeight - verticalPadding, containerHeight); 319 const targetContainerRatio = targetMaxWidth / targetMaxHeight; 320 if (originalRatio > targetContainerRatio) { 321 // If targetMaxWidth is reached before targetMaxHeight. 322 containerWidth = targetMaxWidth; 323 containerHeight = containerWidth / originalRatio; 324 } else { 325 // If targetMaxHeight is reached before targetMaxWidth. 326 containerHeight = targetMaxHeight; 327 containerWidth = containerHeight * originalRatio; 328 } 329 const containerScale = originalWidth / containerWidth; 330 const lightboxImgWidth = imgMaxWidth * (containerWidth / containerMaxWidth); 331 const lightboxImgHeight = imgMaxHeight * (containerHeight / containerMaxHeight); 332 333 // As of this writing, using the calculations above will render the 334 // lightbox with a small, erroneous whitespace on the left side of the 335 // image in iOS Safari, perhaps due to an inconsistency in how browsers 336 // handle absolute positioning and CSS transformation. In any case, 337 // adding 1 pixel to the container width and height solves the problem, 338 // though this can be removed if the issue is fixed in the future. 339 state.overlayStyles = ` 340 :root { 341 --wp--lightbox-initial-top-position: $screenPosY}px; 342 --wp--lightbox-initial-left-position: $screenPosX}px; 343 --wp--lightbox-container-width: $containerWidth + 1}px; 344 --wp--lightbox-container-height: $containerHeight + 1}px; 345 --wp--lightbox-image-width: $lightboxImgWidth}px; 346 --wp--lightbox-image-height: $lightboxImgHeight}px; 347 --wp--lightbox-scale: $containerScale}; 348 --wp--lightbox-scrollbar-width: $window.innerWidth - document.documentElement.clientWidth}px; 349 } 350 `; 351 }, 352 setButtonStyles() { 353 const { 354 imageId 355 } = (0,interactivity_namespaceObject.getContext)(); 356 const { 357 ref 358 } = (0,interactivity_namespaceObject.getElement)(); 359 state.metadata[imageId].imageRef = ref; 360 state.metadata[imageId].currentSrc = ref.currentSrc; 361 const { 362 naturalWidth, 363 naturalHeight, 364 offsetWidth, 365 offsetHeight 366 } = ref; 367 368 // If the image isn't loaded yet, it can't calculate where the button 369 // should be. 370 if (naturalWidth === 0 || naturalHeight === 0) { 371 return; 372 } 373 const figure = ref.parentElement; 374 const figureWidth = ref.parentElement.clientWidth; 375 376 // It needs special handling for the height because a caption will cause 377 // the figure to be taller than the image, which means it needs to 378 // account for that when calculating the placement of the button in the 379 // top right corner of the image. 380 let figureHeight = ref.parentElement.clientHeight; 381 const caption = figure.querySelector('figcaption'); 382 if (caption) { 383 const captionComputedStyle = window.getComputedStyle(caption); 384 if (!['absolute', 'fixed'].includes(captionComputedStyle.position)) { 385 figureHeight = figureHeight - caption.offsetHeight - parseFloat(captionComputedStyle.marginTop) - parseFloat(captionComputedStyle.marginBottom); 386 } 387 } 388 const buttonOffsetTop = figureHeight - offsetHeight; 389 const buttonOffsetRight = figureWidth - offsetWidth; 390 let imageButtonTop = buttonOffsetTop + 16; 391 let imageButtonRight = buttonOffsetRight + 16; 392 393 // In the case of an image with object-fit: contain, the size of the 394 // <img> element can be larger than the image itself, so it needs to 395 // calculate where to place the button. 396 if (state.metadata[imageId].scaleAttr === 'contain') { 397 // Natural ratio of the image. 398 const naturalRatio = naturalWidth / naturalHeight; 399 // Offset ratio of the image. 400 const offsetRatio = offsetWidth / offsetHeight; 401 if (naturalRatio >= offsetRatio) { 402 // If it reaches the width first, it keeps the width and compute the 403 // height. 404 const referenceHeight = offsetWidth / naturalRatio; 405 imageButtonTop = (offsetHeight - referenceHeight) / 2 + buttonOffsetTop + 16; 406 imageButtonRight = buttonOffsetRight + 16; 407 } else { 408 // If it reaches the height first, it keeps the height and compute 409 // the width. 410 const referenceWidth = offsetHeight * naturalRatio; 411 imageButtonTop = buttonOffsetTop + 16; 412 imageButtonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16; 413 } 414 } 415 state.metadata[imageId].imageButtonTop = imageButtonTop; 416 state.metadata[imageId].imageButtonRight = imageButtonRight; 417 }, 418 setOverlayFocus() { 419 if (state.overlayEnabled) { 420 // Moves the focus to the dialog when it opens. 421 const { 422 ref 423 } = (0,interactivity_namespaceObject.getElement)(); 424 ref.focus(); 425 } 426 }, 427 initTriggerButton() { 428 const { 429 imageId 430 } = (0,interactivity_namespaceObject.getContext)(); 431 const { 432 ref 433 } = (0,interactivity_namespaceObject.getElement)(); 434 state.metadata[imageId].buttonRef = ref; 435 } 436 } 437 }, { 438 lock: true 439 }); 440
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |