sul-dlss/SearchWorks

View on GitHub
app/javascript/jquery.preview-gallery.js

Summary

Maintainability
A
0 mins
Test Coverage
import PreviewContent from './preview-content'

(function($) {

  /*
    jQuery plugin to attach gallery preview triggers and render previews in
    gallery view

      Usage: $(selector).previewGallery();

    This plugin :
      - adds preview triggers to the gallery preview button
      - on preview click event, fetches preview content from
        'data-preview-url' data attribute value and renders it
  */


  $.fn.previewGallery = function() {

    return this.each(function() {
      var $item = $(this),
          $previewTarget = $($item.data('preview-target')),
          $triggerBtn, $closeBtn, $arrow, $gallery, $itemsPerRow, $itemWidth;

      init();
      attachTriggerEvents();

      function showPreview() {
        var previewUrl = $item.data('preview-url')

        $previewTarget.addClass('preview').empty();

        PreviewContent.append(previewUrl, $previewTarget);

        appendPointer($previewTarget);

        $previewTarget.css('display', 'inline-block');

        $previewTarget.append($closeBtn).show();

        $triggerBtn.html('Close');

        attachPreviewEvents();

        $triggerBtn.addClass('preview-open');
      }

      function clamp(x, min, max) {
        return Math.min(Math.max(x, min), max);
      }

      function appendPointer($target) {
        $target.append($arrow);

        const maxLeft = $target.width() - $arrow.width() - 1
        const { left, width } = $item[0].getBoundingClientRect()
        const docsLeft = document.getElementById('documents').getBoundingClientRect().left
        const arrowLeft = clamp(left - docsLeft + width / 2 - 10, 0, maxLeft)

        $arrow.css('left', arrowLeft);
      }


      function attachTriggerEvents() {
        $item.find($triggerBtn).on('click', $.proxy(function(e) {
          if (previewOpen()){
            closePreview();
          }else{
            showPreview();
          }
        }, this));

        $("#documents").on('click', $.proxy(function(e) {
          if (!currentPreview(e)){
            closePreview();
          }
        }, this));
      }

      function currentPreview(e){
        // Check if we're clicking in a preview
        if ($(e.target).parents('.preview-container').length > 0){
          return true;
        }else{
          if (e.target === $triggerBtn[0]) {
            return true;
          }else{
            return false;
          }
        }
      }

      function previewOpen(){
        if ($triggerBtn.hasClass('preview-open')){
          return true;
        }else{
          return false;
        }
      }



      function attachPreviewEvents() {
        $previewTarget.find($closeBtn).on('click', $.proxy(function() {
          closePreview();
        }, this));
      }

      function closePreview() {
        $previewTarget.removeClass('preview');
        $triggerBtn.removeClass('preview-open');
        $previewTarget.hide();
        $triggerBtn.html('Preview');
      }

      function itemsPerRow() {
        var width = $('#documents').width();
        return  Math.floor(width/$itemWidth);
      }

      function reorderPreviewDivs() {
        const docId = $previewTarget.data('document-id');
        var galleryDocs = $(`.gallery-document`)
        var previewIndex = galleryDocs.index($(`.gallery-document[data-doc-id='${docId}']`)) + 1;

        $itemsPerRow = itemsPerRow();
        /* 
        / If $itemsPerRow is NaN or 0 we should return here. If not we are going 
        / to have a bad time with an infinite while loop. This only manifests
        / on the show page when using the "back" button to get back to a show
        / page using the browse nearby feature.
        /
        / Reproduction steps for NaN:
        / 1. visit https://searchworks.stanford.edu/view/2279186
        / 2. click on the bound-with link "Copy 1 bound with v. 5, no. 1. 36105026515499 (item id)"
        / 3. click the back button
        /
        */
        if (Number.isNaN($itemsPerRow) || $itemsPerRow === 0) {
          return;
        }

        if ($previewTarget.find($arrow)){
          appendPointer($previewTarget);
        }

        while (previewIndex % $itemsPerRow !== 0){
          previewIndex++;
        }
        if (previewIndex > galleryDocs.length){
          previewIndex = galleryDocs.length;
        }
        var detachedPreview = $previewTarget.detach();
        $($gallery[(previewIndex-1)]).after($previewTarget);
      }


      function init() {
        $itemWidth = $item.outerWidth() + 10;
        $triggerBtn = $item.find('*[data-behavior="preview-button-trigger"]');
        $closeBtn = $(`<button type="button" class="preview-close btn-close close" aria-label="Close">
        <span aria-hidden="true" class="visually-hidden">×</span>
        </button>`);
        $arrow = $('<div class="preview-arrow"></div>');
        $gallery = $('.gallery-document');
        reorderPreviewDivs();
        $(window).resize(function() {
          reorderPreviewDivs();
        });
      }
    });

  };

})(jQuery);


Blacklight.onLoad(function() {
  $('*[data-behavior="preview-gallery"]').previewGallery();
});