[ 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.mjs
   2  import {
   3    store,
   4    getContext,
   5    getElement,
   6    getConfig,
   7    withSyncEvent,
   8    withScope,
   9    splitTask
  10  } from "@wordpress/interactivity";
  11  
  12  // packages/block-library/build-module/utils/reduced-motion.mjs
  13  function prefersReducedMotion() {
  14    return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches === true;
  15  }
  16  
  17  // packages/block-library/build-module/image/constants.mjs
  18  var IMAGE_PRELOAD_DELAY = 200;
  19  
  20  // packages/block-library/build-module/image/view.mjs
  21  var isTouching = false;
  22  var lastTouchTime = 0;
  23  var touchStartEvent = {
  24    startX: 0,
  25    startY: 0,
  26    startTime: 0
  27  };
  28  var inertElements = [];
  29  var touchDrag = {
  30    isDragging: false,
  31    direction: null,
  32    // The elements the gesture moves. The drag offset is written on these
  33    // rather than on the overlay, whose `style` attribute is bound to
  34    // `state.overlayStyles`: the framework rewrites that attribute whole
  35    // whenever the bound value changes, so a resize part way through a gesture
  36    // used to wipe the drag out from under the finger. Nothing is bound to the
  37    // containers, so what is written here stays written.
  38    slideEls: [],
  39    // Animations currently running on `slideEls`, so an interrupted gesture can
  40    // stop them.
  41    animations: [],
  42    // Finishes a committed swipe once its slide is over. Held so that a new
  43    // gesture can settle a swipe still in flight rather than stranding it.
  44    settle: null
  45  };
  46  var SLIDE_DURATION_MS = 220;
  47  var FADE_DURATION_MS = 300;
  48  var SLIDE_EASING = "cubic-bezier(0.2, 0.7, 0.2, 1)";
  49  var DIRECTION_LATCH_THRESHOLD_PX = 10;
  50  var HORIZONTAL_DOMINANCE_RATIO = 1.5;
  51  var COMMIT_DISTANCE_RATIO = 0.2;
  52  var FLICK_DISTANCE_PX = 50;
  53  var FLICK_MAX_DURATION_MS = 300;
  54  function getSlidePitch() {
  55    return window.innerWidth;
  56  }
  57  function slideTransform(offset) {
  58    return `translate(calc(-50% + $offset}px), -50%)`;
  59  }
  60  function setDragOffset(els, offset) {
  61    els.forEach((el) => {
  62      if (offset) {
  63        el.style.setProperty(
  64          "--wp--lightbox-drag-offset",
  65          `$offset}px`
  66        );
  67      } else {
  68        el.style.removeProperty("--wp--lightbox-drag-offset");
  69      }
  70    });
  71  }
  72  function stopDragAnimations() {
  73    touchDrag.animations.forEach((animation) => animation.cancel());
  74    touchDrag.animations = [];
  75  }
  76  function resetTouchDrag() {
  77    touchDrag.isDragging = false;
  78    touchDrag.direction = null;
  79    touchDrag.slideEls = [];
  80  }
  81  async function waitForImage(img) {
  82    await splitTask();
  83    try {
  84      await img?.decode();
  85    } catch {
  86    }
  87  }
  88  var focusableSelectors = [
  89    ".wp-lightbox-close-button",
  90    ".wp-lightbox-navigation-button"
  91  ];
  92  function getImageSrc({ uploadedSrc }) {
  93    return uploadedSrc || "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
  94  }
  95  function getImageSrcset({ lightboxSrcset }) {
  96    return lightboxSrcset || "";
  97  }
  98  function getImageMetadata(imageId) {
  99    const metadata = state.metadata[imageId];
 100    return Object.hasOwn(state.metadata, imageId) ? metadata : void 0;
 101  }
 102  var { state, actions, callbacks } = store(
 103    "core/image",
 104    {
 105      state: {
 106        selectedImageId: null,
 107        selectedGalleryId: null,
 108        preloadTimers: /* @__PURE__ */ new Map(),
 109        preloadedImageIds: /* @__PURE__ */ new Set(),
 110        get galleryImages() {
 111          if (!state.selectedGalleryId) {
 112            return [state.selectedImageId];
 113          }
 114          return Object.entries(state.metadata).filter(
 115            ([, value]) => value.galleryId === state.selectedGalleryId
 116          ).sort(([, a], [, b]) => {
 117            const orderA = a.order ?? 0;
 118            const orderB = b.order ?? 0;
 119            return orderA - orderB;
 120          }).map(([key]) => key);
 121        },
 122        get selectedImageIndex() {
 123          return state.galleryImages.findIndex(
 124            (id) => id === state.selectedImageId
 125          );
 126        },
 127        get selectedImage() {
 128          return getImageMetadata(state.selectedImageId);
 129        },
 130        get hasNavigationIcon() {
 131          const { navigationButtonType } = state.selectedImage;
 132          return navigationButtonType === "icon" || navigationButtonType === "both";
 133        },
 134        get hasNavigationText() {
 135          const { navigationButtonType } = state.selectedImage;
 136          return navigationButtonType === "text" || navigationButtonType === "both";
 137        },
 138        get thisImage() {
 139          const { imageId } = getContext();
 140          return getImageMetadata(imageId);
 141        },
 142        get hasNavigation() {
 143          return state.galleryImages.length > 1;
 144        },
 145        get hasNextImage() {
 146          return state.selectedImageIndex + 1 < state.galleryImages.length;
 147        },
 148        get hasPreviousImage() {
 149          return state.selectedImageIndex - 1 >= 0;
 150        },
 151        get overlayOpened() {
 152          return state.selectedImageId !== null;
 153        },
 154        get roleAttribute() {
 155          return state.overlayOpened ? "dialog" : null;
 156        },
 157        get ariaModal() {
 158          return state.overlayOpened ? "true" : null;
 159        },
 160        get ariaLabel() {
 161          return state.selectedImage.customAriaLabel || getConfig().defaultAriaLabel;
 162        },
 163        get closeButtonAriaLabel() {
 164          return state.hasNavigationText ? void 0 : getConfig().closeButtonText;
 165        },
 166        get prevButtonAriaLabel() {
 167          return state.hasNavigationText ? void 0 : getConfig().prevButtonText;
 168        },
 169        get nextButtonAriaLabel() {
 170          return state.hasNavigationText ? void 0 : getConfig().nextButtonText;
 171        },
 172        get enlargedSrc() {
 173          return getImageSrc(state.selectedImage);
 174        },
 175        get enlargedSrcset() {
 176          return getImageSrcset(state.selectedImage);
 177        },
 178        get figureStyles() {
 179          return state.overlayOpened && `$state.selectedImage.figureStyles?.replace(
 180            /margin[^;]*;?/g,
 181            ""
 182          )};`;
 183        },
 184        get imgStyles() {
 185          return state.overlayOpened && `$state.selectedImage.imgStyles?.replace(
 186            /;$/,
 187            ""
 188          )}; object-fit:cover;`;
 189        },
 190        get isContentHidden() {
 191          const ctx = getContext();
 192          return state.overlayEnabled && state.selectedImageId === ctx.imageId;
 193        },
 194        get isContentVisible() {
 195          const ctx = getContext();
 196          return !state.overlayEnabled && state.selectedImageId === ctx.imageId;
 197        }
 198      },
 199      actions: {
 200        showLightbox() {
 201          const { imageId } = getContext();
 202          if (!getImageMetadata(imageId)?.imageRef?.complete) {
 203            return;
 204          }
 205          state.scrollTopReset = document.documentElement.scrollTop;
 206          state.scrollLeftReset = document.documentElement.scrollLeft;
 207          state.selectedImageId = imageId;
 208          const { galleryId } = getContext("core/gallery") || {};
 209          state.selectedGalleryId = galleryId || null;
 210          state.overlayEnabled = true;
 211          callbacks.setOverlayStyles();
 212        },
 213        hideLightbox() {
 214          if (state.overlayEnabled) {
 215            state.overlayEnabled = false;
 216            setTimeout(function() {
 217              state.selectedImage.buttonRef.focus({
 218                preventScroll: true
 219              });
 220              state.selectedImageId = null;
 221              state.selectedGalleryId = null;
 222            }, 450);
 223          }
 224        },
 225        showPreviousImage: withSyncEvent((event) => {
 226          event.stopPropagation();
 227          const nextIndex = state.hasPreviousImage ? state.selectedImageIndex - 1 : state.galleryImages.length - 1;
 228          state.selectedImageId = state.galleryImages[nextIndex];
 229          callbacks.setOverlayStyles();
 230        }),
 231        showNextImage: withSyncEvent((event) => {
 232          event.stopPropagation();
 233          const nextIndex = state.hasNextImage ? state.selectedImageIndex + 1 : 0;
 234          state.selectedImageId = state.galleryImages[nextIndex];
 235          callbacks.setOverlayStyles();
 236        }),
 237        handleKeydown: withSyncEvent((event) => {
 238          if (state.overlayEnabled) {
 239            if (event.key === "Escape") {
 240              actions.hideLightbox();
 241            } else if (event.key === "ArrowLeft") {
 242              actions.showPreviousImage(event);
 243            } else if (event.key === "ArrowRight") {
 244              actions.showNextImage(event);
 245            } else if (event.key === "Tab") {
 246              const focusableElements = Array.from(
 247                document.querySelectorAll(focusableSelectors)
 248              );
 249              const firstFocusableElement = focusableElements[0];
 250              const lastFocusableElement = focusableElements[focusableElements.length - 1];
 251              if (event.shiftKey && event.target === firstFocusableElement) {
 252                event.preventDefault();
 253                lastFocusableElement.focus();
 254              } else if (!event.shiftKey && event.target === lastFocusableElement) {
 255                event.preventDefault();
 256                firstFocusableElement.focus();
 257              }
 258            }
 259          }
 260        }),
 261        handleTouchMove: withSyncEvent((event) => {
 262          if (!state.overlayEnabled) {
 263            return;
 264          }
 265          event.preventDefault();
 266          const t = event.touches && event.touches[0];
 267          if (!t || !state.hasNavigation) {
 268            return;
 269          }
 270          const deltaX = t.clientX - touchStartEvent.startX;
 271          const deltaY = t.clientY - touchStartEvent.startY;
 272          const absDeltaX = Math.abs(deltaX);
 273          const absDeltaY = Math.abs(deltaY);
 274          if (!touchDrag.direction && (absDeltaX > DIRECTION_LATCH_THRESHOLD_PX || absDeltaY > DIRECTION_LATCH_THRESHOLD_PX)) {
 275            touchDrag.direction = absDeltaX > absDeltaY ? "horizontal" : "vertical";
 276            touchDrag.slideEls = Array.from(
 277              event.currentTarget.querySelectorAll(
 278                ".lightbox-image-container"
 279              )
 280            );
 281          }
 282          if (touchDrag.direction === "horizontal" && touchDrag.slideEls.length) {
 283            touchDrag.isDragging = true;
 284            setDragOffset(touchDrag.slideEls, deltaX);
 285          }
 286        }),
 287        handleTouchStart(event) {
 288          isTouching = true;
 289          if (event.touches?.length > 1) {
 290            return;
 291          }
 292          const t = event.touches && event.touches[0];
 293          if (t) {
 294            touchStartEvent.startX = t.clientX;
 295            touchStartEvent.startY = t.clientY;
 296            touchStartEvent.startTime = Date.now();
 297          }
 298          touchDrag.settle?.();
 299          stopDragAnimations();
 300          resetTouchDrag();
 301        },
 302        handleTouchCancel() {
 303          stopDragAnimations();
 304          setDragOffset(touchDrag.slideEls, 0);
 305          resetTouchDrag();
 306          lastTouchTime = Date.now();
 307          isTouching = false;
 308        },
 309        handleTouchEnd: withSyncEvent((event) => {
 310          if (event.touches?.length) {
 311            return;
 312          }
 313          const touchEndEvent = event.changedTouches && event.changedTouches[0] || event.touches && event.touches[0];
 314          const now = Date.now();
 315          if (touchEndEvent && state.overlayEnabled && touchDrag.isDragging) {
 316            event.preventDefault();
 317            const deltaX = touchEndEvent.clientX - touchStartEvent.startX;
 318            const deltaY = touchEndEvent.clientY - touchStartEvent.startY;
 319            const absDeltaX = Math.abs(deltaX);
 320            const absDeltaY = Math.abs(deltaY);
 321            const elapsedMs = now - touchStartEvent.startTime;
 322            const slidePitch = getSlidePitch();
 323            const isHorizontalDominant = absDeltaX > absDeltaY * HORIZONTAL_DOMINANCE_RATIO;
 324            const pastDistanceThreshold = absDeltaX > slidePitch * COMMIT_DISTANCE_RATIO;
 325            const isFastFlick = absDeltaX > FLICK_DISTANCE_PX && elapsedMs < FLICK_MAX_DURATION_MS;
 326            const shouldCommit = isHorizontalDominant && (pastDistanceThreshold || isFastFlick);
 327            const showsNextImage = deltaX < 0;
 328            const slideEls = touchDrag.slideEls;
 329            const reducedMotion = prefersReducedMotion();
 330            const committedOffset = showsNextImage ? -slidePitch : slidePitch;
 331            const endOffset = shouldCommit ? committedOffset : 0;
 332            const settle = () => {
 333              if (touchDrag.settle !== settle) {
 334                return;
 335              }
 336              touchDrag.settle = null;
 337              stopDragAnimations();
 338              setDragOffset(slideEls, 0);
 339              if (!shouldCommit) {
 340                return;
 341              }
 342              if (showsNextImage) {
 343                actions.showNextImage(event);
 344              } else {
 345                actions.showPreviousImage(event);
 346              }
 347              if (reducedMotion) {
 348                return;
 349              }
 350              const hold = slideEls.map(
 351                (el) => el.animate([{ opacity: 0 }, { opacity: 0 }], {
 352                  fill: "forwards"
 353                })
 354              );
 355              touchDrag.animations = hold;
 356              const enlargedEl = slideEls[slideEls.length - 1];
 357              waitForImage(enlargedEl.querySelector("img")).then(
 358                () => {
 359                  if (touchDrag.animations !== hold) {
 360                    return;
 361                  }
 362                  stopDragAnimations();
 363                  touchDrag.animations = slideEls.map(
 364                    (el) => el.animate(
 365                      [
 366                        { opacity: 0 },
 367                        {
 368                          opacity: el === enlargedEl ? 1 : 0
 369                        }
 370                      ],
 371                      {
 372                        duration: FADE_DURATION_MS,
 373                        easing: "ease-out"
 374                      }
 375                    )
 376                  );
 377                }
 378              );
 379            };
 380            touchDrag.settle = settle;
 381            if (reducedMotion) {
 382              settle();
 383            } else {
 384              touchDrag.animations = slideEls.map(
 385                (el) => el.animate(
 386                  [
 387                    { transform: slideTransform(deltaX) },
 388                    {
 389                      transform: slideTransform(endOffset)
 390                    }
 391                  ],
 392                  {
 393                    duration: SLIDE_DURATION_MS,
 394                    easing: SLIDE_EASING,
 395                    // Holds the end position until `settle()` has
 396                    // moved the slides there itself.
 397                    fill: "forwards"
 398                  }
 399                )
 400              );
 401              touchDrag.animations[0].onfinish = withScope(settle);
 402            }
 403          }
 404          lastTouchTime = now;
 405          isTouching = false;
 406          resetTouchDrag();
 407        }),
 408        handleScroll() {
 409          if (state.overlayOpened) {
 410            if (!isTouching && Date.now() - lastTouchTime > 450) {
 411              window.scrollTo(
 412                state.scrollLeftReset,
 413                state.scrollTopReset
 414              );
 415            }
 416          }
 417        },
 418        preloadImage() {
 419          const { imageId } = getContext();
 420          if (state.preloadedImageIds.has(imageId)) {
 421            return;
 422          }
 423          const imageMetadata = getImageMetadata(imageId);
 424          if (!imageMetadata) {
 425            return;
 426          }
 427          const imageLink = document.createElement("link");
 428          imageLink.rel = "preload";
 429          imageLink.as = "image";
 430          imageLink.href = getImageSrc(imageMetadata);
 431          const srcset = getImageSrcset(imageMetadata);
 432          if (srcset) {
 433            imageLink.setAttribute("imagesrcset", srcset);
 434            imageLink.setAttribute("imagesizes", "100vw");
 435          }
 436          document.head.appendChild(imageLink);
 437          state.preloadedImageIds.add(imageId);
 438        },
 439        preloadImageWithDelay() {
 440          const { imageId } = getContext();
 441          actions.cancelPreload();
 442          const timerId = setTimeout(
 443            withScope(() => {
 444              actions.preloadImage();
 445              state.preloadTimers.delete(imageId);
 446            }),
 447            IMAGE_PRELOAD_DELAY
 448          );
 449          state.preloadTimers.set(imageId, timerId);
 450        },
 451        cancelPreload() {
 452          const { imageId } = getContext();
 453          if (state.preloadTimers.has(imageId)) {
 454            clearTimeout(state.preloadTimers.get(imageId));
 455            state.preloadTimers.delete(imageId);
 456          }
 457        }
 458      },
 459      callbacks: {
 460        setOverlayStyles() {
 461          if (!state.overlayEnabled) {
 462            return;
 463          }
 464          let {
 465            naturalWidth,
 466            naturalHeight,
 467            offsetWidth: originalWidth,
 468            offsetHeight: originalHeight
 469          } = state.selectedImage.imageRef;
 470          let { x: screenPosX, y: screenPosY } = state.selectedImage.imageRef.getBoundingClientRect();
 471          const naturalRatio = naturalWidth / naturalHeight;
 472          const originalRatio = originalWidth / originalHeight;
 473          if (state.selectedImage.scaleAttr === "contain") {
 474            if (naturalRatio > originalRatio) {
 475              const heightWithoutSpace = originalWidth / naturalRatio;
 476              screenPosY += (originalHeight - heightWithoutSpace) / 2;
 477              originalHeight = heightWithoutSpace;
 478            } else {
 479              const widthWithoutSpace = originalHeight * naturalRatio;
 480              screenPosX += (originalWidth - widthWithoutSpace) / 2;
 481              originalWidth = widthWithoutSpace;
 482            }
 483          }
 484          const imgMaxWidth = parseFloat(
 485            state.selectedImage.targetWidth && state.selectedImage.targetWidth !== "none" ? state.selectedImage.targetWidth : naturalWidth
 486          );
 487          const imgMaxHeight = parseFloat(
 488            state.selectedImage.targetHeight && state.selectedImage.targetHeight !== "none" ? state.selectedImage.targetHeight : naturalHeight
 489          );
 490          const fullSizeRatio = imgMaxWidth / imgMaxHeight;
 491          let containerWidth = imgMaxWidth;
 492          let containerHeight = imgMaxHeight;
 493          if (originalWidth > containerWidth || originalHeight > containerHeight) {
 494            containerWidth = originalWidth;
 495            containerHeight = originalHeight;
 496          }
 497          let horizontalPadding = 0;
 498          let verticalPadding = 160;
 499          if (480 < window.innerWidth) {
 500            horizontalPadding = 80;
 501            verticalPadding = 160;
 502          }
 503          if (960 < window.innerWidth) {
 504            horizontalPadding = state.hasNavigation ? 320 : 80;
 505            verticalPadding = 80;
 506          }
 507          const targetMaxWidth = Math.min(
 508            window.innerWidth - horizontalPadding,
 509            containerWidth
 510          );
 511          const targetMaxHeight = Math.min(
 512            window.innerHeight - verticalPadding,
 513            containerHeight
 514          );
 515          const targetContainerRatio = targetMaxWidth / targetMaxHeight;
 516          if (fullSizeRatio > targetContainerRatio) {
 517            containerWidth = targetMaxWidth;
 518            containerHeight = containerWidth / fullSizeRatio;
 519          } else {
 520            containerHeight = targetMaxHeight;
 521            containerWidth = containerHeight * fullSizeRatio;
 522          }
 523          const hasCroppedSource = naturalRatio.toFixed(2) !== fullSizeRatio.toFixed(2);
 524          const sourceRatio = hasCroppedSource ? naturalRatio : fullSizeRatio;
 525          const containerScale = Math.max(
 526            originalWidth / containerWidth,
 527            originalHeight / containerHeight,
 528            originalWidth / (containerHeight * sourceRatio),
 529            originalHeight * sourceRatio / containerWidth
 530          );
 531          const thumbnailWidth = originalWidth / containerScale;
 532          const thumbnailHeight = originalHeight / containerScale;
 533          const cropX = (containerWidth - thumbnailWidth) / 2;
 534          const cropY = (containerHeight - thumbnailHeight) / 2;
 535          screenPosX -= cropX * containerScale;
 536          screenPosY -= cropY * containerScale;
 537          state.overlayStyles = `
 538                      --wp--lightbox-initial-top-position: $screenPosY}px;
 539                      --wp--lightbox-initial-left-position: $screenPosX}px;
 540                      --wp--lightbox-container-width: $containerWidth + 1}px;
 541                      --wp--lightbox-container-height: $containerHeight + 1}px;
 542                      --wp--lightbox-image-width: $containerWidth}px;
 543                      --wp--lightbox-image-height: $containerHeight}px;
 544                      --wp--lightbox-initial-clip: inset($cropY}px $cropX}px);
 545                      --wp--lightbox-thumbnail-width: $hasCroppedSource ? thumbnailWidth : containerWidth}px;
 546                      --wp--lightbox-thumbnail-height: $hasCroppedSource ? thumbnailHeight : containerHeight}px;
 547                      --wp--lightbox-scale: $containerScale};
 548                      --wp--lightbox-scrollbar-width: $window.innerWidth - document.documentElement.clientWidth}px;
 549                  `;
 550        },
 551        setButtonStyles() {
 552          const { ref } = getElement();
 553          if (!ref) {
 554            return;
 555          }
 556          const { imageId } = getContext();
 557          const imageMetadata = getImageMetadata(imageId);
 558          if (!imageMetadata) {
 559            return;
 560          }
 561          imageMetadata.imageRef = ref;
 562          imageMetadata.currentSrc = ref.currentSrc;
 563          const {
 564            naturalWidth,
 565            naturalHeight,
 566            offsetWidth,
 567            offsetHeight
 568          } = ref;
 569          if (naturalWidth === 0 || naturalHeight === 0) {
 570            return;
 571          }
 572          const figure = ref.parentElement;
 573          const figureWidth = ref.parentElement.clientWidth;
 574          let figureHeight = ref.parentElement.clientHeight;
 575          const caption = figure.querySelector("figcaption");
 576          if (caption) {
 577            const captionComputedStyle = window.getComputedStyle(caption);
 578            if (!["absolute", "fixed"].includes(
 579              captionComputedStyle.position
 580            )) {
 581              figureHeight = figureHeight - caption.offsetHeight - parseFloat(captionComputedStyle.marginTop) - parseFloat(captionComputedStyle.marginBottom);
 582            }
 583          }
 584          const buttonOffsetTop = figureHeight - offsetHeight;
 585          const buttonOffsetRight = figureWidth - offsetWidth;
 586          let buttonTop = buttonOffsetTop + 16;
 587          let buttonRight = buttonOffsetRight + 16;
 588          if (imageMetadata.scaleAttr === "contain") {
 589            const naturalRatio = naturalWidth / naturalHeight;
 590            const offsetRatio = offsetWidth / offsetHeight;
 591            if (naturalRatio >= offsetRatio) {
 592              const referenceHeight = offsetWidth / naturalRatio;
 593              buttonTop = (offsetHeight - referenceHeight) / 2 + buttonOffsetTop + 16;
 594              buttonRight = buttonOffsetRight + 16;
 595            } else {
 596              const referenceWidth = offsetHeight * naturalRatio;
 597              buttonTop = buttonOffsetTop + 16;
 598              buttonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16;
 599            }
 600          }
 601          imageMetadata.buttonTop = buttonTop;
 602          imageMetadata.buttonRight = buttonRight;
 603        },
 604        setOverlayFocus() {
 605          if (state.overlayEnabled) {
 606            const { ref } = getElement();
 607            ref.focus();
 608          }
 609        },
 610        setInertElements() {
 611          if (!state.overlayEnabled) {
 612            inertElements.forEach(
 613              (el) => el.removeAttribute("inert")
 614            );
 615            inertElements = [];
 616            return;
 617          }
 618          const { ref } = getElement();
 619          let node = ref;
 620          while (node && node !== document.body && node.parentElement) {
 621            for (const sibling of node.parentElement.children) {
 622              if (sibling !== node && !sibling.hasAttribute("inert")) {
 623                sibling.setAttribute("inert", "");
 624                inertElements.push(sibling);
 625              }
 626            }
 627            node = node.parentElement;
 628          }
 629        },
 630        initTriggerButton() {
 631          const { imageId } = getContext();
 632          const { ref } = getElement();
 633          const imageMetadata = getImageMetadata(imageId);
 634          if (imageMetadata) {
 635            imageMetadata.buttonRef = ref;
 636          }
 637        }
 638      }
 639    },
 640    { lock: true }
 641  );


Generated : Sat Oct 31 08:20:35 2026 Cross-referenced by PHPXref