Created
August 26, 2026 18:18
-
-
Save dpw1/a1343e51c06f33bf15678dad09925f75 to your computer and use it in GitHub Desktop.
EZFY Debut theme product image zoom snippet plus Theme settings schema.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ,{ | |
| "name": "EZFY Product Image Zoom", | |
| "settings": [ | |
| { | |
| "type": "paragraph", | |
| "content": "Please save and view the website outside of the Customize page to see the changes." | |
| }, | |
| { | |
| "type": "checkbox", | |
| "id": "ezfy_zoom_enable", | |
| "label": "Enable lightbox zoom", | |
| "default": true | |
| }, | |
| { | |
| "type": "select", | |
| "id": "ezfy_zoom_type", | |
| "label": "On desktop, activate the lightbox via:", | |
| "info": "Choose whether the zoom is activated by clicking on the image or by clicking on the magnifying glass button.", | |
| "options": [ | |
| { | |
| "value": "button", | |
| "label": "Button" | |
| }, | |
| { | |
| "value": "click", | |
| "label": "Image click" | |
| } | |
| ], | |
| "default": "click" | |
| }, | |
| { | |
| "type": "select", | |
| "id": "ezfy_zoom_type_mobile", | |
| "label": "On mobile, activate the lightbox via:", | |
| "info": "Choose whether the zoom is activated by clicking on the image or by clicking on the magnifying glass button.", | |
| "options": [ | |
| { | |
| "value": "button", | |
| "label": "Button" | |
| }, | |
| { | |
| "value": "click", | |
| "label": "Image click" | |
| } | |
| ], | |
| "default": "click" | |
| } | |
| ] | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {% if settings.ezfy_zoom_enable and template contains 'product' %} | |
| <div style="height:0;width:0;display:none" | |
| data_ezfy_zoom_type_mobile="{{ settings.ezfy_zoom_type_mobile }}" | |
| data_ezfy_zoom_type="{{ settings.ezfy_zoom_type }}" | |
| data_ezfy_zoom_block_slider="false" | |
| ></div> | |
| <style> | |
| .pswp{display:none;position:absolute;width:100%;height:100%;left:0;top:0;overflow:hidden;-ms-touch-action:none;touch-action:none;z-index:1500;-webkit-text-size-adjust:100%;-webkit-backface-visibility:hidden;outline:0}.pswp *{-webkit-box-sizing:border-box;box-sizing:border-box}.pswp img{max-width:none}.pswp--animate_opacity{opacity:.001;will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--open{display:block}.pswp--zoom-allowed .pswp__img{cursor:-webkit-zoom-in;cursor:-moz-zoom-in;cursor:zoom-in}.pswp--zoomed-in .pswp__img{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.pswp--dragging .pswp__img{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.pswp__bg{position:absolute;left:0;top:0;width:100%;height:100%;background:#000;opacity:0;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-backface-visibility:hidden;will-change:opacity}.pswp__scroll-wrap{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden}.pswp__container,.pswp__zoom-wrap{-ms-touch-action:none;touch-action:none;position:absolute;left:0;right:0;top:0;bottom:0}.pswp__container,.pswp__img{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pswp__zoom-wrap{position:absolute;width:100%;-webkit-transform-origin:left top;-ms-transform-origin:left top;transform-origin:left top;-webkit-transition:-webkit-transform 333ms cubic-bezier(.4,0,.22,1);transition:transform 333ms cubic-bezier(.4,0,.22,1)}.pswp__bg{will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--animated-in .pswp__bg,.pswp--animated-in .pswp__zoom-wrap{-webkit-transition:none;transition:none}.pswp__container,.pswp__zoom-wrap{-webkit-backface-visibility:hidden}.pswp__item{position:absolute;left:0;right:0;top:0;bottom:0;overflow:hidden}.pswp__img{position:absolute;width:auto;height:auto;top:0;left:0}.pswp__img--placeholder{-webkit-backface-visibility:hidden}.pswp__img--placeholder--blank{background:#222}.pswp--ie .pswp__img{width:100%!important;height:auto!important;left:0;top:0}.pswp__error-msg{position:absolute;left:0;top:50%;width:100%;text-align:center;font-size:14px;line-height:16px;margin-top:-8px;color:#ccc}.pswp__error-msg a{color:#ccc;text-decoration:underline} | |
| .pswp__button{width:44px;height:44px;position:relative;background:0 0;cursor:pointer;overflow:visible;-webkit-appearance:none;display:block;border:0;padding:0;margin:0;float:right;opacity:.75;-webkit-transition:opacity .2s;transition:opacity .2s;-webkit-box-shadow:none;box-shadow:none}.pswp__button:focus,.pswp__button:hover{opacity:1}.pswp__button:active{outline:0;opacity:.9}.pswp__button::-moz-focus-inner{padding:0;border:0}.pswp__ui--over-close .pswp__button--close{opacity:1}.pswp__button,.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{background:url(default-skin.png) 0 0 no-repeat;background-size:264px 88px;width:44px;height:44px}@media (-webkit-min-device-pixel-ratio:1.1),(-webkit-min-device-pixel-ratio:1.09375),(min-resolution:105dpi),(min-resolution:1.1dppx){.pswp--svg .pswp__button,.pswp--svg .pswp__button--arrow--left:before,.pswp--svg .pswp__button--arrow--right:before{background-image:url(default-skin.svg)}.pswp--svg .pswp__button--arrow--left,.pswp--svg .pswp__button--arrow--right{background:0 0}}.pswp__button--close{background-position:0 -44px}.pswp__button--share{background-position:-44px -44px}.pswp__button--fs{display:none}.pswp--supports-fs .pswp__button--fs{display:block}.pswp--fs .pswp__button--fs{background-position:-44px 0}.pswp__button--zoom{display:none;background-position:-88px 0}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__button--zoom{background-position:-132px 0}.pswp--touch .pswp__button--arrow--left,.pswp--touch .pswp__button--arrow--right{visibility:hidden}.pswp__button--arrow--left,.pswp__button--arrow--right{background:0 0;top:50%;margin-top:-50px;width:70px;height:100px;position:absolute}.pswp__button--arrow--left{left:0}.pswp__button--arrow--right{right:0}.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{content:'';top:35px;background-color:rgba(0,0,0,.3);height:30px;width:32px;position:absolute}.pswp__button--arrow--left:before{left:6px;background-position:-138px -44px}.pswp__button--arrow--right:before{right:6px;background-position:-94px -44px}.pswp__counter,.pswp__share-modal{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pswp__share-modal{display:block;background:rgba(0,0,0,.5);width:100%;height:100%;top:0;left:0;padding:10px;position:absolute;z-index:1600;opacity:0;-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out;-webkit-backface-visibility:hidden;will-change:opacity}.pswp__share-modal--hidden{display:none}.pswp__share-tooltip{z-index:1620;position:absolute;background:#fff;top:56px;border-radius:2px;display:block;width:auto;right:44px;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.25);box-shadow:0 2px 5px rgba(0,0,0,.25);-webkit-transform:translateY(6px);-ms-transform:translateY(6px);transform:translateY(6px);-webkit-transition:-webkit-transform .25s;transition:transform .25s;-webkit-backface-visibility:hidden;will-change:transform}.pswp__share-tooltip a{display:block;padding:8px 12px;color:#000;text-decoration:none;font-size:14px;line-height:18px}.pswp__share-tooltip a:hover{text-decoration:none;color:#000}.pswp__share-tooltip a:first-child{border-radius:2px 2px 0 0}.pswp__share-tooltip a:last-child{border-radius:0 0 2px 2px}.pswp__share-modal--fade-in{opacity:1}.pswp__share-modal--fade-in .pswp__share-tooltip{-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.pswp--touch .pswp__share-tooltip a{padding:16px 12px}a.pswp__share--facebook:before{content:'';display:block;width:0;height:0;position:absolute;top:-12px;right:15px;border:6px solid transparent;border-bottom-color:#fff;-webkit-pointer-events:none;-moz-pointer-events:none;pointer-events:none}a.pswp__share--facebook:hover{background:#3e5c9a;color:#fff}a.pswp__share--facebook:hover:before{border-bottom-color:#3e5c9a}a.pswp__share--twitter:hover{background:#55acee;color:#fff}a.pswp__share--pinterest:hover{background:#ccc;color:#ce272d}a.pswp__share--download:hover{background:#ddd}.pswp__counter{position:absolute;left:0;top:0;height:44px;font-size:13px;line-height:44px;color:#fff;opacity:.75;padding:0 10px}.pswp__caption{position:absolute;left:0;bottom:0;width:100%;min-height:44px}.pswp__caption small{font-size:11px;color:#bbb}.pswp__caption__center{text-align:left;max-width:420px;margin:0 auto;font-size:13px;padding:10px;line-height:20px;color:#ccc}.pswp__caption--empty{display:none}.pswp__caption--fake{visibility:hidden}.pswp__preloader{width:44px;height:44px;position:absolute;top:0;left:50%;margin-left:-22px;opacity:0;-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out;will-change:opacity;direction:ltr}.pswp__preloader__icn{width:20px;height:20px;margin:12px}.pswp__preloader--active{opacity:1}.pswp__preloader--active .pswp__preloader__icn{background:url(preloader.gif) 0 0 no-repeat}.pswp--css_animation .pswp__preloader--active{opacity:1}.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn{-webkit-animation:clockwise .5s linear infinite;animation:clockwise .5s linear infinite}.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut{-webkit-animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite;animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite}.pswp--css_animation .pswp__preloader__icn{background:0 0;opacity:.75;width:14px;height:14px;position:absolute;left:15px;top:15px;margin:0}.pswp--css_animation .pswp__preloader__cut{position:relative;width:7px;height:14px;overflow:hidden}.pswp--css_animation .pswp__preloader__donut{-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;border:2px solid #fff;border-radius:50%;border-left-color:transparent;border-bottom-color:transparent;position:absolute;top:0;left:0;background:0 0;margin:0}@media screen and (max-width:1024px){.pswp__preloader{position:relative;left:auto;top:auto;margin:0;float:right}}@-webkit-keyframes clockwise{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes clockwise{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes donut-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(-140deg);transform:rotate(-140deg)}100%{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes donut-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(-140deg);transform:rotate(-140deg)}100%{-webkit-transform:rotate(0);transform:rotate(0)}}.pswp__ui{-webkit-font-smoothing:auto;visibility:visible;opacity:1;z-index:1550}.pswp__top-bar{position:absolute;left:0;top:0;height:44px;width:100%}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right,.pswp__caption,.pswp__top-bar{-webkit-backface-visibility:hidden;will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right{visibility:visible}.pswp__caption,.pswp__top-bar{background-color:rgba(0,0,0,.5)}.pswp__ui--fit .pswp__caption,.pswp__ui--fit .pswp__top-bar{background-color:rgba(0,0,0,.3)}.pswp__ui--idle .pswp__top-bar{opacity:0}.pswp__ui--idle .pswp__button--arrow--left,.pswp__ui--idle .pswp__button--arrow--right{opacity:0}.pswp__ui--hidden .pswp__button--arrow--left,.pswp__ui--hidden .pswp__button--arrow--right,.pswp__ui--hidden .pswp__caption,.pswp__ui--hidden .pswp__top-bar{opacity:.001}.pswp__ui--one-slide .pswp__button--arrow--left,.pswp__ui--one-slide .pswp__button--arrow--right,.pswp__ui--one-slide .pswp__counter{display:none}.pswp__element--disabled{display:none!important}.pswp--minimal--dark .pswp__top-bar{background:0 0} | |
| </style> | |
| <style> | |
| /* Images */ | |
| .product-single__photos, | |
| .product-single__media-wrapper{ | |
| {% if settings.ezfy_zoom_type == 'click' %} | |
| cursor: -moz-zoom-in; | |
| cursor: -webkit-zoom-in; | |
| cursor: zoom-in; | |
| {% endif %} | |
| } | |
| .FeaturedImage--block-lightbox *{ | |
| pointer-events: none; | |
| } | |
| .product-single__media-group [id*='FeaturedMedia'][tabindex]{ | |
| position: relative; | |
| } | |
| /* Zoom button */ | |
| .EzfyZoom-button *{ | |
| pointer-events: none; | |
| } | |
| .EzfyZoom-button{ | |
| border-radius: 50%; | |
| width: 34px; | |
| height: 34px; | |
| padding: 0 !important; | |
| position: absolute; | |
| right: 12px; | |
| bottom: 12px; | |
| background: white; | |
| box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; | |
| cursor: -moz-zoom-in; | |
| cursor: -webkit-zoom-in; | |
| cursor: zoom-in; | |
| opacity: 0; | |
| transition: opacity 1s ease-in-out; | |
| } | |
| .EzfyZoom-button:hover{ | |
| background: white !important; | |
| } | |
| .EzfyZoom-button svg{ | |
| fill: black !important; | |
| width: 13.75px; | |
| height: 13.75px; | |
| position: relative; | |
| top: 2px; | |
| } | |
| @keyframes fade-in { | |
| 0% { | |
| opacity: 0; | |
| } | |
| 100% { | |
| opacity: 1; | |
| } | |
| } | |
| [id*='FeaturedMedia'] .EzfyZoom-button, | |
| .product-single__photo .EzfyZoom-button{ | |
| -webkit-animation: fade-in .5s cubic-bezier(0.39, 0.575, 0.565, 1) both; | |
| animation: fade-in .5s cubic-bezier(0.39, 0.575, 0.565, 1) both; | |
| } | |
| .EzfyZoom-button:active, | |
| .EzfyZoom-button:visited, | |
| .EzfyZoom-button:focus{ | |
| background: unset !important; | |
| } | |
| /* PhotoSwipe general styles | |
| ================================ */ | |
| #ezfyLightbox .pswp__custom-controls{ | |
| position: absolute; | |
| display: flex !important; | |
| bottom: 30px; | |
| left: 0; | |
| right: 0; | |
| transform: translateY(0); | |
| transition: transform .32s; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| #ezfyLightbox .pswp__button[class*='arrow']{ | |
| margin-top: unset; | |
| } | |
| #ezfyLightbox .pswp__custom-controls .pswp__button{ | |
| background: white; | |
| border-radius: 50%; | |
| width: 49px; | |
| height: 49px; | |
| opacity: 1; | |
| position: relative; | |
| box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; | |
| transition: unset !important; | |
| transform: unset !important; | |
| visibility: visible; | |
| -webkit-tap-highlight-color: rgba(255, 255, 255, 0); | |
| } | |
| #ezfyLightbox .pswp__custom-controls .pswp__button svg{ | |
| width: 13px !important; | |
| height: 13px !important; | |
| margin: 8px; | |
| pointer-events: none; | |
| } | |
| #ezfyLightbox svg{ | |
| pointer-events: none; | |
| } | |
| #ezfyLightbox .pswp__button:before { | |
| display: none; | |
| } | |
| .pswp__ui--hidden .pswp__custom-controls{ | |
| transform: translateY(100px) !important; | |
| } | |
| #ezfyLightbox .pswp__custom-controls .pswp__button--close{ | |
| width: 60px; | |
| height: 60px; | |
| margin-left: 25px; | |
| margin-right: 25px; | |
| } | |
| #ezfyLightbox .pswp__custom-controls .pswp__button--close svg{ | |
| position: relative; | |
| top: 2px; | |
| } | |
| #ezfyLightbox .pswp__top-bar{ | |
| display: none; | |
| } | |
| .EzfyZoom-button{ | |
| z-index: 10; | |
| } | |
| /* Custom styles | |
| ================================ */ | |
| #ezfyLightbox .pswp__bg{ | |
| background: white !important; | |
| } | |
| </style> | |
| <div id="ezfyLightbox" class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> | |
| <!-- Background of PhotoSwipe. | |
| It's a separate element as animating opacity is faster than rgba(). --> | |
| <div class="pswp__bg"></div> | |
| <!-- Slides wrapper with overflow:hidden. --> | |
| <div class="pswp__scroll-wrap"> | |
| <!-- Container that holds slides. | |
| PhotoSwipe keeps only 3 of them in the DOM to save memory. | |
| Don't modify these 3 pswp__item elements, data is added later on. --> | |
| <div class="pswp__container"> | |
| <div class="pswp__item"></div> | |
| <div class="pswp__item"></div> | |
| <div class="pswp__item"></div> | |
| </div> | |
| <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. --> | |
| <div class="pswp__ui pswp__ui--hidden"> | |
| <div class="pswp__top-bar"> | |
| <!-- Controls are self-explanatory. Order can be changed. --> | |
| <div class="pswp__counter"></div> | |
| <button class="pswp__button pswp__button--share" title="Share"></button> | |
| <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button> | |
| <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button> | |
| <!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR --> | |
| <!-- element will get class pswp__preloader--active when preloader is running --> | |
| <div class="pswp__preloader"> | |
| <div class="pswp__preloader__icn"> | |
| <div class="pswp__preloader__cut"> | |
| <div class="pswp__preloader__donut"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> | |
| <div class="pswp__share-tooltip"></div> | |
| </div> | |
| <div class="pswp__custom-controls"> | |
| <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"> | |
| <svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-arrow-left" viewBox="0 0 284.49 498.98"><path d="M249.49 0a35 35 0 0 1 24.75 59.75L84.49 249.49l189.75 189.74a35.002 35.002 0 1 1-49.5 49.5L10.25 274.24a35 35 0 0 1 0-49.5L224.74 10.25A34.89 34.89 0 0 1 249.49 0z"></path></svg> | |
| </button> | |
| <button class="pswp__button pswp__button--close" title="Close (Esc)"> | |
| <svg xmlns="http://www.w3.org/2000/svg" id="Capa_1" enable-background="new 0 0 413.348 413.348" height="512" viewBox="0 0 413.348 413.348" width="512"><path d="m413.348 24.354-24.354-24.354-182.32 182.32-182.32-182.32-24.354 24.354 182.32 182.32-182.32 182.32 24.354 24.354 182.32-182.32 182.32 182.32 24.354-24.354-182.32-182.32z"/></svg> | |
| </button> | |
| <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"> | |
| <svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-arrow-right" viewBox="0 0 284.49 498.98"><path d="M35 498.98a35 35 0 0 1-24.75-59.75l189.74-189.74L10.25 59.75a35.002 35.002 0 0 1 49.5-49.5l214.49 214.49a35 35 0 0 1 0 49.5L59.75 488.73A34.89 34.89 0 0 1 35 498.98z"></path></svg> | |
| </button> | |
| </div> | |
| <div class="pswp__caption"> | |
| <div class="pswp__caption__center"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| /*ezfybeautify*/ | |
| /* | |
| [EZFYLICENSE] | |
| 1.7.1: | |
| - Improved compatibility with all debut versions | |
| 1.7.0: | |
| - Slider images not showing in some older Debut versions | |
| 1.6.0: | |
| - Multiple fixes and compatibility to older debuts | |
| 1.5.0: | |
| - Removed unnecessary options | |
| 1.4.0 | |
| - Lightbox zoom "click to zoom" for mobile fix | |
| 1.3.0 | |
| - Lightbox zoom button only on mobile | |
| 1.2.0 | |
| - Added option to block lightbox zoom. | |
| - Refactor JS code. | |
| 1.1.0 | |
| - Loads only at the product page | |
| 1.0.9 | |
| - Position relative for images to keep button inside | |
| 1.0.8 | |
| - Added zoom options for desktop/mobile | |
| 1.0.7 | |
| - Added zoom button | |
| - Added 'settings_schema' options | |
| 1.0.6 | |
| - Updated zoom to work with multiple videos under the Non-slider debut | |
| 1.0.5 | |
| - Zoom working correctly with latest Debut Slider version (accepts multiple videos) | |
| 1.0.4 | |
| - Added short delay after loading photswipe to avoid bugs | |
| 1.0.3 | |
| - moved parent/child selectors to init of function | |
| - renamed function | |
| 1.0.2 | |
| - Fix blurry images when opening lightbox | |
| 1.0.1 | |
| - Hide top bar | |
| 1.0.0 | |
| - Stylized back, close & next buttons | |
| [EZFYLICENSE] | |
| */ | |
| window.ezfyLightboxZoomDebut = window.ezfyLightboxZoomDebut || {}; | |
| ezfyLightboxZoomDebut = (function() { | |
| let IS_DEBUT_SLIDER = false; | |
| const DELAY_AFTER_LOADING_PHOTO_SWIPE = 250; | |
| const CSS_PRODUCT_IMAGE_TAG = `img.feature-row__image` | |
| const CSS_PRODUCT_IMAGE_PARENT = `.product-single__media-wrapper > .product-single__media, .product-single__photo` | |
| const CSS_PARENT = `.product-single__media-group, .product-single__photos`; | |
| /* This is used to detect which thumbnail must be clicked after the | |
| zoomed image changes. | |
| Make sure to replace the "replace_index' with the correct number */ | |
| const CSS_THUMBNAIL_CLICKABLE = `.product-single__thumbnails > *:nth-child(REPLACE_INDEX) a, [class*='product-single__thumbnails'] > li:nth-child(REPLACE_INDEX) a` | |
| const CSS_INDIVIDUAL_SLIDE = `.product-single__photo, .product-single__media` | |
| const CLASS_INDIVIDUAL_SLIDE = [`product-single__photo`, ] | |
| const ZOOM_TYPE = (() => { | |
| function _isMobile() { | |
| return window.matchMedia("(max-width: 767px)").matches | |
| } | |
| if (_isMobile()) { | |
| let $el = document.querySelector(`[data_ezfy_zoom_type_mobile]`); | |
| return $el.getAttribute(`data_ezfy_zoom_type_mobile`); | |
| } | |
| let $el = document.querySelector(`[data_ezfy_zoom_type]`); | |
| return $el.getAttribute(`data_ezfy_zoom_type`); | |
| })(); | |
| const options = { | |
| blockSlider: _getAttributeOption(`data_ezfy_zoom_block_slider`) | |
| } | |
| function _getAttributeOption(dataAttribute) { | |
| const element = document.querySelector(`[${dataAttribute}]`); | |
| if (!element) { | |
| return null; | |
| } | |
| const attr = element.getAttribute(dataAttribute); | |
| if (attr === 'true') { | |
| return true; | |
| } else if (attr === 'false') { | |
| return false | |
| } else { | |
| return attr; | |
| } | |
| } | |
| const _detectParentSelector = () => { | |
| // using debut slider | |
| if (document.querySelector(`#featuredImageSlider`)) { | |
| IS_DEBUT_SLIDER = true; | |
| return "#featuredImageSlider .flickity-slider"; | |
| } | |
| // using default debut | |
| return CSS_PARENT; | |
| } | |
| const CSS_PARENT_SELECTOR = _detectParentSelector(); | |
| function _loadScript(src) { | |
| return new Promise(function(resolve, reject) { | |
| var s; | |
| s = document.createElement("script"); | |
| s.src = src; | |
| s.onload = resolve; | |
| s.onerror = reject; | |
| document.head.appendChild(s); | |
| }); | |
| } | |
| function _isProductPage() { | |
| return /product/.test(window.location.href); | |
| } | |
| async function _getCurrentProductImages() { | |
| return new Promise(async (resolve, reject) => { | |
| const url = `${window.location.origin}/${window.location.pathname}.json`; | |
| let response = await fetch(url); | |
| let data = await response.json(); | |
| console.log(data); | |
| resolve(data.product.images); | |
| }); | |
| } | |
| function _sleep(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| async function loadPhotoswipe() { | |
| return new Promise(async (resolve, reject) => { | |
| await _loadScript(`https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js`); | |
| await _loadScript(`https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe-ui-default.min.js`); | |
| resolve(); | |
| }); | |
| } | |
| /* Adds essential data attributes for the images to be clickable. */ | |
| async function addImageSizeDataAttribute() { | |
| const $images = document.querySelectorAll(CSS_PRODUCT_IMAGE_TAG); | |
| if (!$images) { | |
| return; | |
| } | |
| const images = await _getCurrentProductImages(); | |
| for (const [i, each] of $images.entries()) { | |
| const $parent = each.closest(CSS_PRODUCT_IMAGE_PARENT); | |
| const height = images[i].height; | |
| const width = images[i].width; | |
| const src = images[i].src; | |
| $parent.setAttribute("data-size-zoom", `${width}x${height}`); | |
| $parent.setAttribute("data-image-large", src); | |
| $parent.setAttribute("data-ezfy-zoom-type", ZOOM_TYPE); | |
| if (!$parent.hasAttribute(`data-product-media-type-video`)) { | |
| $parent.setAttribute(`data-image-position`, images[i].position) | |
| } | |
| } | |
| if (!IS_DEBUT_SLIDER) { | |
| const $medias = document.querySelectorAll(CSS_PRODUCT_IMAGE_PARENT); | |
| for (const [i, each] of $medias.entries()) { | |
| each.setAttribute("data-slide-index", i); | |
| } | |
| } | |
| } | |
| function initPhotoSwipeZoom() { | |
| var initPhotoSwipeFromDOM = function(gallerySelector) { | |
| /* Gets all images | |
| ======================= */ | |
| var parseThumbnailElements = function(el) { | |
| var $elements = document.querySelectorAll(CSS_PRODUCT_IMAGE_PARENT), | |
| items = [], | |
| linkEl, | |
| size, | |
| item; | |
| for (var i = 0; i < $elements.length; i++) { | |
| const $el = $elements[i]; //child element | |
| // include only element nodes | |
| if ($el.nodeType !== 1) { | |
| continue; | |
| } | |
| if (!$el.getAttribute("data-size-zoom")) { | |
| continue; | |
| } | |
| size = $el.getAttribute('data-size-zoom').split('x'); | |
| // create slide object | |
| item = { | |
| src: $el.getAttribute('data-image-large'), | |
| w: parseInt(size[0], 10), | |
| h: parseInt(size[1], 10) | |
| }; | |
| const $image = $el.querySelector('img'); | |
| item.msrc = $el.getAttribute('data-image-large') | |
| item.imagePosition = $el.getAttribute(`data-image-position`); | |
| item.el = $el; // save link to element for getThumbBoundsFn | |
| items.push(item); | |
| } | |
| return items; | |
| }; | |
| // find nearest parent element | |
| var _closest = function _closest(el, fn) { | |
| return el && (fn(el) ? el : _closest(el.parentNode, fn)); | |
| }; | |
| /* Image or button clicked */ | |
| var onImageClick = function(e) { | |
| e = e || window.event; | |
| e.preventDefault ? e.preventDefault() : e.returnValue = false; | |
| var eTarget = e.target || e.srcElement; | |
| const $parent = eTarget.closest(CSS_PRODUCT_IMAGE_PARENT); | |
| if ($parent){ | |
| const isVideo = $parent.querySelector("video"); | |
| if (isVideo) { | |
| return; | |
| } | |
| } | |
| /* If allowed button only, do not open lightbox */ | |
| if (ZOOM_TYPE === 'button' && !eTarget.classList.contains('EzfyZoom-button')) { | |
| return; | |
| } | |
| // find root element of slide | |
| var clickedListItem = _closest(eTarget, function(el) { | |
| console.log(el); | |
| if (!el || !el.classList){ | |
| return false; | |
| } | |
| return (el.matches(CSS_INDIVIDUAL_SLIDE)); | |
| }); | |
| if (!clickedListItem) { | |
| return; | |
| } | |
| // find index of clicked item by looping through all child nodes | |
| // alternatively, you may define index via data- attribute | |
| const $clickedParent = clickedListItem.parentNode; | |
| var clickedGallery = $clickedParent; | |
| var $children = $clickedParent.querySelectorAll(CSS_INDIVIDUAL_SLIDE); | |
| var totalChildren = $children.length; | |
| var nodeIndex = 0; | |
| var index; | |
| for (var i = 0; i < totalChildren; i++) { | |
| if ($children[i].nodeType !== 1) { | |
| continue; | |
| } | |
| if ($children[i] === clickedListItem) { | |
| index = nodeIndex; | |
| break; | |
| } | |
| nodeIndex++; | |
| } | |
| index = parseInt(clickedListItem.getAttribute(`data-image-position`) ? clickedListItem.getAttribute(`data-image-position`) : clickedListItem.querySelector(`[data-image-position]`).getAttribute(`data-image-position`)) - 1; | |
| if (index >= 0) { | |
| // open PhotoSwipe if valid index found | |
| openPhotoSwipe(index, clickedGallery); | |
| } | |
| return false; | |
| }; | |
| var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) { | |
| var pswpElement = document.querySelectorAll('.pswp')[0], | |
| gallery, | |
| options, | |
| items; | |
| items = parseThumbnailElements(galleryElement); | |
| options = { | |
| barsSize: { | |
| top: 0, | |
| bottom: 'auto' | |
| }, | |
| allowPanToNext: false, | |
| captionEl: false, | |
| closeOnScroll: false, | |
| pinchToClose: false, | |
| tapToToggleControls: false, | |
| history: false, | |
| galleryUID: galleryElement.getAttribute('data-pswp-uid'), | |
| getThumbBoundsFn: function(index) { | |
| // See Options -> getThumbBoundsFn section of documentation for more info | |
| var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail | |
| pageYScroll = window.pageYOffset || document.documentElement.scrollTop, | |
| rect = thumbnail.getBoundingClientRect(); | |
| return { | |
| x: rect.left, | |
| y: rect.top + pageYScroll, | |
| w: rect.width | |
| }; | |
| } | |
| }; | |
| // PhotoSwipe opened from URL | |
| if (fromURL) { | |
| if (options.galleryPIDs) { | |
| // parse real index when custom PIDs are used | |
| // http://photoswipe.com/documentation/faq.html#custom-pid-in-url | |
| for (var j = 0; j < items.length; j++) { | |
| if (items[j].pid == index) { | |
| options.index = j; | |
| break; | |
| } | |
| } | |
| } else { | |
| // in URL indexes start from 1 | |
| options.index = parseInt(index, 10) - 1; | |
| } | |
| } else { | |
| options.index = parseInt(index, 10); | |
| } | |
| // exit if index not found | |
| if (isNaN(options.index)) { | |
| return; | |
| } | |
| if (disableAnimation) { | |
| options.showAnimationDuration = 0; | |
| } | |
| // Pass data to PhotoSwipe and initialize it | |
| gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options); | |
| gallery.init(); | |
| gallery.ui.hideControls(); | |
| gallery.listen('beforeChange', function() { | |
| updateMainSliderImageAsPhotoSwipeChanges(gallery); | |
| }); | |
| }; | |
| // loop through all gallery elements and bind events | |
| var galleryElements = document.querySelectorAll(gallerySelector); | |
| for (var i = 0, l = galleryElements.length; i < l; i++) { | |
| galleryElements[i].setAttribute('data-pswp-uid', i + 1); | |
| galleryElements[i].onclick = onImageClick; | |
| } | |
| }; | |
| // execute above function | |
| initPhotoSwipeFromDOM(CSS_PARENT_SELECTOR); | |
| } | |
| function injectButton() { | |
| if (ZOOM_TYPE !== 'button') { | |
| return; | |
| } | |
| const $button = `<button type="button" class="EzfyZoom-button btn btn--body btn--circle js-photoswipe__zoom product__photo-zoom"> | |
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve"> | |
| <g> | |
| <g> | |
| <path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/> | |
| </g> | |
| </g> | |
| <g> | |
| <g> | |
| <path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/> | |
| </g> | |
| </g> | |
| </svg> | |
| </button>`; | |
| const $images = document.querySelectorAll(CSS_PRODUCT_IMAGE_PARENT); | |
| if (!$images) { | |
| return; | |
| } | |
| for (let each of $images) { | |
| if (each.hasAttribute(`data-product-media-type-video`)) { | |
| continue; | |
| } | |
| each.insertAdjacentHTML('beforeend', $button); | |
| } | |
| } | |
| function updateMainSliderImageAsPhotoSwipeChanges(gallery) { | |
| let index = gallery.getCurrentIndex(); | |
| index = gallery.currItem.imagePosition | |
| const _newIndex = document.querySelector(`[data-image-position='${index}']`); | |
| const getNewIndex = () => { | |
| if (_newIndex.hasAttribute(`data-slide-index`)) { | |
| return parseInt(_newIndex.getAttribute(`data-slide-index`)); | |
| } | |
| } | |
| const newIndex = getNewIndex(); | |
| const i = parseInt(newIndex) + 1; | |
| if (IS_DEBUT_SLIDER && window.ezfyDebutSliderFeatured) { | |
| window.ezfyDebutSliderFeatured.select(newIndex, null, true); | |
| } else { | |
| const selector = CSS_THUMBNAIL_CLICKABLE.replaceAll(`REPLACE_INDEX`, i); | |
| const $thumbnail = document.querySelector(selector); | |
| window.photoSwipeIndex = index; | |
| if ($thumbnail) { | |
| $thumbnail.click(); | |
| } | |
| } | |
| } | |
| function blockLightboxOnSliderDrag() { | |
| if (!IS_DEBUT_SLIDER || !window.ezfyVentureSliderFeatured || !options.blockSlider || _isMobile()) { | |
| return; | |
| } | |
| const _class = 'FeaturedImage--block-lightbox'; | |
| const $image = document.querySelector(`#featuredImageSlider`); | |
| window.ezfyVentureSliderFeatured.on('dragMove', function(event, pointer, moveVector) { | |
| if ($image.classList.contains(_class)) { | |
| return; | |
| } | |
| $image.classList.add(_class); | |
| }); | |
| window.ezfyVentureSliderFeatured.on('dragEnd', function(event, pointer, moveVector) { | |
| $image.classList.remove(_class); | |
| }); | |
| } | |
| return { | |
| init: function() { | |
| document.addEventListener("DOMContentLoaded", async function() { | |
| if (_isProductPage()) { | |
| await loadPhotoswipe(); | |
| await addImageSizeDataAttribute(); | |
| await _sleep(DELAY_AFTER_LOADING_PHOTO_SWIPE); | |
| initPhotoSwipeZoom(); | |
| blockLightboxOnSliderDrag(); | |
| injectButton(); | |
| } | |
| }); | |
| window.addEventListener("resize", function() {}); | |
| window.addEventListener("load", function() {}); | |
| window.addEventListener("scroll", function() {}); | |
| }, | |
| }; | |
| })(); | |
| ezfyLightboxZoomDebut.init(); | |
| </script> | |
| {% endif %} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment