[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/script-modules/block-library/image/ -> view.js (source)

   1  // packages/block-library/build-module/image/view.js
   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.js
  11  var IMAGE_PRELOAD_DELAY = 200;
  12  
  13  // packages/block-library/build-module/image/view.js
  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  );


Generated : Tue Apr 28 08:20:12 2026 Cross-referenced by PHPXref