PhotoSwipe overlayed button click causes gallery to open

542 views Asked by At

I'm trying to add a delete button overlayed on my thumbnails but when I click it the gallery is opened.

I tried adding this to try to stop the click propagating to the figure element but it didn't work:

$('body').on('click', '.delete-file-btn', function(e) {
  e.preventDefault();
  e.stopImmediatePropagation();
});

    var initPhotoSwipeFromDOM = function(gallerySelector) {
      // parse slide data (url, title, size ...) from DOM elements 
      var parseThumbnailElements = function(el) {
          var thumbElements = el.childNodes,
              numNodes = thumbElements.length,
              items = [],
              figureEl,
              linkEl,
              size,
              item;

          for(var i = 0; i < numNodes; i++) {
              figureEl = thumbElements[i]; // <figure> element
              // include only element nodes 
              if(figureEl.nodeType !== 1) {
                  continue;
              }
              linkEl = figureEl.children[0]; // <a> element
              size = linkEl.getAttribute('data-size').split('x');
              // create slide object
              item = {
                  src: linkEl.getAttribute('href'),
                  w: parseInt(size[0], 10),
                  h: parseInt(size[1], 10)
              };

              if(figureEl.children.length > 1) {
                  // <figcaption> content
                  item.title = figureEl.children[1].innerHTML; 
              }
              if(linkEl.children.length > 0) {
                  // <img> thumbnail element, retrieving thumbnail url
                  item.msrc = linkEl.children[0].getAttribute('src');
              } 
              item.el = figureEl; // 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) );
      };

      // triggers when user clicks on thumbnail
      var onThumbnailsClick = function(e) {
          e = e || window.event;
          e.preventDefault ? e.preventDefault() : e.returnValue = false;
          var eTarget = e.target || e.srcElement;
          // find root element of slide
          var clickedListItem = closest(eTarget, function(el) {
              return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
          });
          if(!clickedListItem) {
              return;
          }
          // find index of clicked item by looping through all child nodes
          // alternatively, you may define index via data- attribute
          var clickedGallery = clickedListItem.parentNode,
              childNodes = clickedListItem.parentNode.childNodes,
              numChildNodes = childNodes.length,
              nodeIndex = 0,
              index;
          for (var i = 0; i < numChildNodes; i++) {
              if(childNodes[i].nodeType !== 1) { 
                  continue; 
              }
              if(childNodes[i] === clickedListItem) {
                  index = nodeIndex;
                  break;
              }
              nodeIndex++;
          }

          if(index >= 0) {
              // open PhotoSwipe if valid index found
              openPhotoSwipe( index, clickedGallery );
          }
          return false;
      };

      // parse picture index and gallery index from URL (#&pid=1&gid=2)
      var photoswipeParseHash = function() {
          var hash = window.location.hash.substring(1),
          params = {};
          if(hash.length < 5) {
              return params;
          }
          var vars = hash.split('&');
          for (var i = 0; i < vars.length; i++) {
              if(!vars[i]) {
                  continue;
              }
              var pair = vars[i].split('=');  
              if(pair.length < 2) {
                  continue;
              }           
              params[pair[0]] = pair[1];
          }
          if(params.gid) {
              params.gid = parseInt(params.gid, 10);
          }
          return params;
      };

      var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) {
          var pswpElement = document.querySelectorAll('.pswp')[0],
              gallery,
              options,
              items;
          items = parseThumbnailElements(galleryElement);
          // define options (if needed)
          options = {
              // define gallery index (for URL)
              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();
      };

      // 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 = onThumbnailsClick;
      }

      // Parse URL and open gallery if it contains #&pid=3&gid=1
      var hashData = photoswipeParseHash();
      if(hashData.pid && hashData.gid) {
          openPhotoSwipe( hashData.pid, galleryElements[ hashData.gid - 1 ], true, true );
      }
    };

    initPhotoSwipeFromDOM('.existing-files');
.existing-files {
  margin: 1rem -.5rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.existing-files .file-container {
  padding: .5rem;
  text-align: center;
  display: inline-block;
  position: relative;
}

.delete-file-btn {
  font-size: 0;
  position: absolute;
  display: block;
  transform: scale(1);
  width: 22px;
  height: 22px;
  border-radius: 40px;
  background-color: #E2E8F0;
  top: -1px;
  right: -5px;
  z-index: 100;
  box-shadow: -2px 2px 6px 1px rgba(0, 0, 0, 0.25);
  transition: background-color .15s ease-in-out,box-shadow .15s ease-in-out;
}

.delete-file-btn::after, .delete-file-btn::before {
  content: "";
  display: block;
  position: absolute;
  width: 12px;
  height: 2px;
  background-color: #000000;
  transform: rotate(45deg);
  border-radius: 5px;
  top: 10px;
  left: 5px;
  transition: background-color .15s ease-in-out;
}

.delete-file-btn::after {
  transform: rotate(-45deg);
}

.delete-file-btn:hover, .delete-file-btn:focus, .delete-file-btn:active {
  box-shadow: none;
  background-color: #A0AEC0;
}

.delete-file-btn:hover::after, .delete-file-btn:hover::before, .delete-file-btn:focus::after, .delete-file-btn:focus::before, .delete-file-btn:active::after, .delete-file-btn:active::before {
  background-color: #FFFFFF;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/default-skin/default-skin.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe-ui-default.js"></script>


<div class="existing-files">
<figure class="file-container">
<a data-size="304x171" data-turbolinks="false" class="gal" href="https://placeimg.com/304/171/nature"><img src="https://placeimg.com/304/171/nature"></a>
<a class="delete-file-btn" rel="nofollow" data-method="delete" href="#"></a>
</figure>
<figure class="file-container">
<a data-size="304x171" data-turbolinks="false" class="gal" href="https://placeimg.com/304/171/nature"><img src="https://placeimg.com/304/171/nature"></a>
<a class="delete-file-btn" rel="nofollow" data-method="delete" href="#"></a>
</figure>
</div>
      
<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div 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--close" title="Close (Esc)"></button>

                <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>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

1

There are 1 answers

0
Mark Robinson On

Instead of preventing the click from propagating on elements it shouldn't I changed the script to only allow clicks on my gallery image anchor element class="gal" above. Here's the edited function from the script above.

      var onThumbnailsClick = function(e) {
      e = e || window.event;
      e.preventDefault ? e.preventDefault() : e.returnValue = false;
      var eTarget = e.target || e.srcElement;
      // find root element of slide
      var clickedListItem = closest(eTarget, function(el) {
          return (el.tagName && el.tagName.toUpperCase() === 'A' && el.className == 'gal');
      });
      if(!clickedListItem) {
          return;
      }
      // find index of clicked item by looping through all child nodes
      // alternatively, you may define index via data- attribute
      var clickedGallery = clickedListItem.parentNode.parentNode,
          childNodes = clickedListItem.parentNode.parentNode.childNodes,
          numChildNodes = childNodes.length,
          nodeIndex = 0,
          index;
      for (var i = 0; i < numChildNodes; i++) {
          if(childNodes[i].nodeType !== 1) { 
              continue; 
          }
          if(childNodes[i] === clickedListItem.parentNode) {
              index = nodeIndex;
              break;
          }
          nodeIndex++;
      }

      if(index >= 0) {
          // open PhotoSwipe if valid index found
          openPhotoSwipe( index, clickedGallery );
      }
      return false;
  };