wp/wp-includes/blocks/image/view.js
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
    21 /******/ })();
    21 /******/ })();
    22 /******/ 
    22 /******/ 
    23 /************************************************************************/
    23 /************************************************************************/
    24 var __webpack_exports__ = {};
    24 var __webpack_exports__ = {};
    25 
    25 
    26 ;// CONCATENATED MODULE: external "@wordpress/interactivity"
    26 ;// external "@wordpress/interactivity"
    27 var x = (y) => {
    27 var x = (y) => {
    28 	var x = {}; __webpack_require__.d(x, y); return x
    28 	var x = {}; __webpack_require__.d(x, y); return x
    29 } 
    29 } 
    30 var y = (x) => (() => (x))
    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) });
    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), ["withSyncEvent"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.withSyncEvent) });
    32 ;// CONCATENATED MODULE: ./node_modules/@wordpress/block-library/build-module/image/view.js
    32 ;// ./node_modules/@wordpress/block-library/build-module/image/view.js
    33 /**
    33 /**
    34  * WordPress dependencies
    34  * WordPress dependencies
    35  */
    35  */
    36 
    36 
    37 
    37 
    48  * for touch and mouse input.
    48  * for touch and mouse input.
    49  *
    49  *
    50  * @type {number}
    50  * @type {number}
    51  */
    51  */
    52 let lastTouchTime = 0;
    52 let lastTouchTime = 0;
    53 
       
    54 /**
       
    55  * Stores the image reference of the currently opened lightbox.
       
    56  *
       
    57  * @type {HTMLElement}
       
    58  */
       
    59 let imageRef;
       
    60 
       
    61 /**
       
    62  * Stores the button reference of the currently opened lightbox.
       
    63  *
       
    64  * @type {HTMLElement}
       
    65  */
       
    66 let buttonRef;
       
    67 const {
    53 const {
    68   state,
    54   state,
    69   actions,
    55   actions,
    70   callbacks
    56   callbacks
    71 } = (0,interactivity_namespaceObject.store)('core/image', {
    57 } = (0,interactivity_namespaceObject.store)('core/image', {
    72   state: {
    58   state: {
    73     currentImage: {},
    59     currentImageId: null,
       
    60     get currentImage() {
       
    61       return state.metadata[state.currentImageId];
       
    62     },
    74     get overlayOpened() {
    63     get overlayOpened() {
    75       return state.currentImage.currentSrc;
    64       return state.currentImageId !== null;
    76     },
    65     },
    77     get roleAttribute() {
    66     get roleAttribute() {
    78       return state.overlayOpened ? 'dialog' : null;
    67       return state.overlayOpened ? 'dialog' : null;
    79     },
    68     },
    80     get ariaModal() {
    69     get ariaModal() {
    81       return state.overlayOpened ? 'true' : null;
    70       return state.overlayOpened ? 'true' : null;
    82     },
    71     },
    83     get enlargedSrc() {
    72     get enlargedSrc() {
    84       return state.currentImage.uploadedSrc || 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
    73       return state.currentImage.uploadedSrc || 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
    85     },
    74     },
       
    75     get figureStyles() {
       
    76       return state.overlayOpened && `${state.currentImage.figureStyles?.replace(/margin[^;]*;?/g, '')};`;
       
    77     },
    86     get imgStyles() {
    78     get imgStyles() {
    87       return state.overlayOpened && `${state.currentImage.imgStyles?.replace(/;$/, '')}; object-fit:cover;`;
    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;
    88     }
   100     }
    89   },
   101   },
    90   actions: {
   102   actions: {
    91     showLightbox() {
   103     showLightbox() {
    92       const ctx = (0,interactivity_namespaceObject.getContext)();
   104       const {
       
   105         imageId
       
   106       } = (0,interactivity_namespaceObject.getContext)();
    93 
   107 
    94       // Bails out if the image has not loaded yet.
   108       // Bails out if the image has not loaded yet.
    95       if (!ctx.imageRef?.complete) {
   109       if (!state.metadata[imageId].imageRef?.complete) {
    96         return;
   110         return;
    97       }
   111       }
    98 
   112 
    99       // Stores the positons of the scroll to fix it until the overlay is
   113       // Stores the positions of the scroll to fix it until the overlay is
   100       // closed.
   114       // closed.
   101       state.scrollTopReset = document.documentElement.scrollTop;
   115       state.scrollTopReset = document.documentElement.scrollTop;
   102       state.scrollLeftReset = document.documentElement.scrollLeft;
   116       state.scrollLeftReset = document.documentElement.scrollLeft;
   103 
   117 
   104       // Moves the information of the expaned image to the state.
   118       // Sets the current expanded image in the state and enables the overlay.
   105       ctx.currentSrc = ctx.imageRef.currentSrc;
       
   106       imageRef = ctx.imageRef;
       
   107       buttonRef = ctx.buttonRef;
       
   108       state.currentImage = ctx;
       
   109       state.overlayEnabled = true;
   119       state.overlayEnabled = true;
       
   120       state.currentImageId = imageId;
   110 
   121 
   111       // Computes the styles of the overlay for the animation.
   122       // Computes the styles of the overlay for the animation.
   112       callbacks.setOverlayStyles();
   123       callbacks.setOverlayStyles();
   113     },
   124     },
   114     hideLightbox() {
   125     hideLightbox() {
   115       if (state.overlayEnabled) {
   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 
   116         // Waits until the close animation has completed before allowing a
   132         // Waits until the close animation has completed before allowing a
   117         // user to scroll again. The duration of this animation is defined in
   133         // user to scroll again. The duration of this animation is defined in
   118         // the `styles.scss` file, but in any case we should wait a few
   134         // the `styles.scss` file, but in any case we should wait a few
   119         // milliseconds longer than the duration, otherwise a user may scroll
   135         // milliseconds longer than the duration, otherwise a user may scroll
   120         // too soon and cause the animation to look sloppy.
   136         // too soon and cause the animation to look sloppy.
   121         setTimeout(function () {
   137         setTimeout(function () {
   122           // Delays before changing the focus. Otherwise the focus ring will
   138           // Delays before changing the focus. Otherwise the focus ring will
   123           // appear on Firefox before the image has finished animating, which
   139           // appear on Firefox before the image has finished animating, which
   124           // looks broken.
   140           // looks broken.
   125           buttonRef.focus({
   141           state.currentImage.buttonRef.focus({
   126             preventScroll: true
   142             preventScroll: true
   127           });
   143           });
   128 
   144 
   129           // Resets the current image to mark the overlay as closed.
   145           // Resets the current image id to mark the overlay as closed.
   130           state.currentImage = {};
   146           state.currentImageId = null;
   131           imageRef = null;
       
   132           buttonRef = null;
       
   133         }, 450);
   147         }, 450);
   134 
   148       }
   135         // Starts the overlay closing animation. The showClosingAnimation
   149     },
   136         // class is used to avoid showing it on page load.
   150     handleKeydown: (0,interactivity_namespaceObject.withSyncEvent)(event => {
   137         state.showClosingAnimation = true;
       
   138         state.overlayEnabled = false;
       
   139       }
       
   140     },
       
   141     handleKeydown(event) {
       
   142       if (state.overlayEnabled) {
   151       if (state.overlayEnabled) {
   143         // Focuses the close button when the user presses the tab key.
   152         // Focuses the close button when the user presses the tab key.
   144         if (event.key === 'Tab') {
   153         if (event.key === 'Tab') {
   145           event.preventDefault();
   154           event.preventDefault();
   146           const {
   155           const {
   151         // Closes the lightbox when the user presses the escape key.
   160         // Closes the lightbox when the user presses the escape key.
   152         if (event.key === 'Escape') {
   161         if (event.key === 'Escape') {
   153           actions.hideLightbox();
   162           actions.hideLightbox();
   154         }
   163         }
   155       }
   164       }
   156     },
   165     }),
   157     handleTouchMove(event) {
   166     handleTouchMove: (0,interactivity_namespaceObject.withSyncEvent)(event => {
   158       // On mobile devices, prevents triggering the scroll event because
   167       // On mobile devices, prevents triggering the scroll event because
   159       // otherwise the page jumps around when it resets the scroll position.
   168       // otherwise the page jumps around when it resets the scroll position.
   160       // This also means that closing the lightbox requires that a user
   169       // This also means that closing the lightbox requires that a user
   161       // perform a simple tap. This may be changed in the future if there is a
   170       // perform a simple tap. This may be changed in the future if there is a
   162       // better alternative to override or reset the scroll position during
   171       // better alternative to override or reset the scroll position during
   163       // swipe actions.
   172       // swipe actions.
   164       if (state.overlayEnabled) {
   173       if (state.overlayEnabled) {
   165         event.preventDefault();
   174         event.preventDefault();
   166       }
   175       }
   167     },
   176     }),
   168     handleTouchStart() {
   177     handleTouchStart() {
   169       isTouching = true;
   178       isTouching = true;
   170     },
   179     },
   171     handleTouchEnd() {
   180     handleTouchEnd() {
   172       // Waits a few milliseconds before resetting to ensure that pinch to
   181       // Waits a few milliseconds before resetting to ensure that pinch to
   195       }
   204       }
   196     }
   205     }
   197   },
   206   },
   198   callbacks: {
   207   callbacks: {
   199     setOverlayStyles() {
   208     setOverlayStyles() {
   200       if (!imageRef) {
   209       if (!state.overlayEnabled) {
   201         return;
   210         return;
   202       }
   211       }
   203       let {
   212       let {
   204         naturalWidth,
   213         naturalWidth,
   205         naturalHeight,
   214         naturalHeight,
   206         offsetWidth: originalWidth,
   215         offsetWidth: originalWidth,
   207         offsetHeight: originalHeight
   216         offsetHeight: originalHeight
   208       } = imageRef;
   217       } = state.currentImage.imageRef;
   209       let {
   218       let {
   210         x: screenPosX,
   219         x: screenPosX,
   211         y: screenPosY
   220         y: screenPosY
   212       } = imageRef.getBoundingClientRect();
   221       } = state.currentImage.imageRef.getBoundingClientRect();
   213 
   222 
   214       // Natural ratio of the image clicked to open the lightbox.
   223       // Natural ratio of the image clicked to open the lightbox.
   215       const naturalRatio = naturalWidth / naturalHeight;
   224       const naturalRatio = naturalWidth / naturalHeight;
   216       // Original ratio of the image clicked to open the lightbox.
   225       // Original ratio of the image clicked to open the lightbox.
   217       let originalRatio = originalWidth / originalHeight;
   226       let originalRatio = originalWidth / originalHeight;
   244       let imgRatio = imgMaxWidth / imgMaxHeight;
   253       let imgRatio = imgMaxWidth / imgMaxHeight;
   245       let containerMaxWidth = imgMaxWidth;
   254       let containerMaxWidth = imgMaxWidth;
   246       let containerMaxHeight = imgMaxHeight;
   255       let containerMaxHeight = imgMaxHeight;
   247       let containerWidth = imgMaxWidth;
   256       let containerWidth = imgMaxWidth;
   248       let containerHeight = imgMaxHeight;
   257       let containerHeight = imgMaxHeight;
       
   258 
   249       // Checks if the target image has a different ratio than the original
   259       // Checks if the target image has a different ratio than the original
   250       // one (thumbnail). Recalculates the width and height.
   260       // one (thumbnail). Recalculates the width and height.
   251       if (naturalRatio.toFixed(2) !== imgRatio.toFixed(2)) {
   261       if (naturalRatio.toFixed(2) !== imgRatio.toFixed(2)) {
   252         if (naturalRatio > imgRatio) {
   262         if (naturalRatio > imgRatio) {
   253           // If the width is reached before the height, it keeps the maxWidth
   263           // If the width is reached before the height, it keeps the maxWidth
   325       // image in iOS Safari, perhaps due to an inconsistency in how browsers
   335       // image in iOS Safari, perhaps due to an inconsistency in how browsers
   326       // handle absolute positioning and CSS transformation. In any case,
   336       // handle absolute positioning and CSS transformation. In any case,
   327       // adding 1 pixel to the container width and height solves the problem,
   337       // adding 1 pixel to the container width and height solves the problem,
   328       // though this can be removed if the issue is fixed in the future.
   338       // though this can be removed if the issue is fixed in the future.
   329       state.overlayStyles = `
   339       state.overlayStyles = `
   330 				:root {
       
   331 					--wp--lightbox-initial-top-position: ${screenPosY}px;
   340 					--wp--lightbox-initial-top-position: ${screenPosY}px;
   332 					--wp--lightbox-initial-left-position: ${screenPosX}px;
   341 					--wp--lightbox-initial-left-position: ${screenPosX}px;
   333 					--wp--lightbox-container-width: ${containerWidth + 1}px;
   342 					--wp--lightbox-container-width: ${containerWidth + 1}px;
   334 					--wp--lightbox-container-height: ${containerHeight + 1}px;
   343 					--wp--lightbox-container-height: ${containerHeight + 1}px;
   335 					--wp--lightbox-image-width: ${lightboxImgWidth}px;
   344 					--wp--lightbox-image-width: ${lightboxImgWidth}px;
   336 					--wp--lightbox-image-height: ${lightboxImgHeight}px;
   345 					--wp--lightbox-image-height: ${lightboxImgHeight}px;
   337 					--wp--lightbox-scale: ${containerScale};
   346 					--wp--lightbox-scale: ${containerScale};
   338 					--wp--lightbox-scrollbar-width: ${window.innerWidth - document.documentElement.clientWidth}px;
   347 					--wp--lightbox-scrollbar-width: ${window.innerWidth - document.documentElement.clientWidth}px;
   339 				}
   348 				`;
   340 			`;
       
   341     },
   349     },
   342     setButtonStyles() {
   350     setButtonStyles() {
   343       const ctx = (0,interactivity_namespaceObject.getContext)();
   351       const {
       
   352         imageId
       
   353       } = (0,interactivity_namespaceObject.getContext)();
   344       const {
   354       const {
   345         ref
   355         ref
   346       } = (0,interactivity_namespaceObject.getElement)();
   356       } = (0,interactivity_namespaceObject.getElement)();
   347       ctx.imageRef = ref;
   357       state.metadata[imageId].imageRef = ref;
       
   358       state.metadata[imageId].currentSrc = ref.currentSrc;
   348       const {
   359       const {
   349         naturalWidth,
   360         naturalWidth,
   350         naturalHeight,
   361         naturalHeight,
   351         offsetWidth,
   362         offsetWidth,
   352         offsetHeight
   363         offsetHeight
   372           figureHeight = figureHeight - caption.offsetHeight - parseFloat(captionComputedStyle.marginTop) - parseFloat(captionComputedStyle.marginBottom);
   383           figureHeight = figureHeight - caption.offsetHeight - parseFloat(captionComputedStyle.marginTop) - parseFloat(captionComputedStyle.marginBottom);
   373         }
   384         }
   374       }
   385       }
   375       const buttonOffsetTop = figureHeight - offsetHeight;
   386       const buttonOffsetTop = figureHeight - offsetHeight;
   376       const buttonOffsetRight = figureWidth - offsetWidth;
   387       const buttonOffsetRight = figureWidth - offsetWidth;
       
   388       let imageButtonTop = buttonOffsetTop + 16;
       
   389       let imageButtonRight = buttonOffsetRight + 16;
   377 
   390 
   378       // In the case of an image with object-fit: contain, the size of the
   391       // In the case of an image with object-fit: contain, the size of the
   379       // <img> element can be larger than the image itself, so it needs to
   392       // <img> element can be larger than the image itself, so it needs to
   380       // calculate where to place the button.
   393       // calculate where to place the button.
   381       if (ctx.scaleAttr === 'contain') {
   394       if (state.metadata[imageId].scaleAttr === 'contain') {
   382         // Natural ratio of the image.
   395         // Natural ratio of the image.
   383         const naturalRatio = naturalWidth / naturalHeight;
   396         const naturalRatio = naturalWidth / naturalHeight;
   384         // Offset ratio of the image.
   397         // Offset ratio of the image.
   385         const offsetRatio = offsetWidth / offsetHeight;
   398         const offsetRatio = offsetWidth / offsetHeight;
   386         if (naturalRatio >= offsetRatio) {
   399         if (naturalRatio >= offsetRatio) {
   387           // If it reaches the width first, it keeps the width and compute the
   400           // If it reaches the width first, it keeps the width and compute the
   388           // height.
   401           // height.
   389           const referenceHeight = offsetWidth / naturalRatio;
   402           const referenceHeight = offsetWidth / naturalRatio;
   390           ctx.imageButtonTop = (offsetHeight - referenceHeight) / 2 + buttonOffsetTop + 16;
   403           imageButtonTop = (offsetHeight - referenceHeight) / 2 + buttonOffsetTop + 16;
   391           ctx.imageButtonRight = buttonOffsetRight + 16;
   404           imageButtonRight = buttonOffsetRight + 16;
   392         } else {
   405         } else {
   393           // If it reaches the height first, it keeps the height and compute
   406           // If it reaches the height first, it keeps the height and compute
   394           // the width.
   407           // the width.
   395           const referenceWidth = offsetHeight * naturalRatio;
   408           const referenceWidth = offsetHeight * naturalRatio;
   396           ctx.imageButtonTop = buttonOffsetTop + 16;
   409           imageButtonTop = buttonOffsetTop + 16;
   397           ctx.imageButtonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16;
   410           imageButtonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16;
   398         }
   411         }
   399       } else {
   412       }
   400         ctx.imageButtonTop = buttonOffsetTop + 16;
   413       state.metadata[imageId].imageButtonTop = imageButtonTop;
   401         ctx.imageButtonRight = buttonOffsetRight + 16;
   414       state.metadata[imageId].imageButtonRight = imageButtonRight;
   402       }
       
   403     },
   415     },
   404     setOverlayFocus() {
   416     setOverlayFocus() {
   405       if (state.overlayEnabled) {
   417       if (state.overlayEnabled) {
   406         // Moves the focus to the dialog when it opens.
   418         // Moves the focus to the dialog when it opens.
   407         const {
   419         const {
   409         } = (0,interactivity_namespaceObject.getElement)();
   421         } = (0,interactivity_namespaceObject.getElement)();
   410         ref.focus();
   422         ref.focus();
   411       }
   423       }
   412     },
   424     },
   413     initTriggerButton() {
   425     initTriggerButton() {
   414       const ctx = (0,interactivity_namespaceObject.getContext)();
   426       const {
       
   427         imageId
       
   428       } = (0,interactivity_namespaceObject.getContext)();
   415       const {
   429       const {
   416         ref
   430         ref
   417       } = (0,interactivity_namespaceObject.getElement)();
   431       } = (0,interactivity_namespaceObject.getElement)();
   418       ctx.buttonRef = ref;
   432       state.metadata[imageId].buttonRef = ref;
   419     }
   433     }
   420   }
   434   }
   421 }, {
   435 }, {
   422   lock: true
   436   lock: true
   423 });
   437 });