Home Reference Source Test Repository

src/components/image_gallery/image_gallery.js

import { Component } from "../../core/bane";
import $ from "jquery";
import PhotoSwipe from "photoswipe";
import PhotoSwipeUI_Default from "photoswipe/dist/photoswipe-ui-default";
import track from "../../core/decorators/track";
import YouTubePlayer from "youtube-player";

// Keep track of instance IDs
let instanceId = 0;

/**
 * A component for creating an Image Gallery
 */
export default class ImageGalleryComponent extends Component {
  /**
   * Render the gallery viewer
   * @return {jQuery} Returns the gallery element
   */
  get $pswp() {
    if (this._$pswp) {
      return this._$pswp;
    }

    return this._$pswp = $(this.template({})).appendTo("body");
  }

  initialize({
    galleryImageSelector = ".stack__article__image-container"
  } = {}) {
    this.template = require("./image_gallery.hbs");

    this.$images = this.$el.find(galleryImageSelector);

    this.events = {
      ["click " + galleryImageSelector]: "onGalleryClick"
    };

    this.$el.attr({
      "data-pswp-uid": ++instanceId,
      "data-gallery": this
    });
  }

  _parseThumbnailElements() {
    if (this._items) {
      return this._items;
    }

    let items = this._items = [];

    this.$images.each((i, el) => {
      let $galleryImage = $(el),
          $linkEl = $galleryImage.find("a"),
          size = $linkEl.attr("data-size").split("x"),
          image = $linkEl.find("img").attr("src"),
          link = $linkEl.attr("href"),
          largeImage = link.match(/\.(jpg|png|gif)/) ? link : image,
          youtubeID = this._youtubeID(link);

      let item = {
        src: largeImage,
        msrc: image,
        el: $linkEl.find("img")[0],
        w: parseInt(size[0], 10),
        h: parseInt(size[1], 10)
      };

      let $caption;
      if (($caption = $galleryImage.find("span")).length) {
        item.title = $caption.html();
      } else if (($caption = $galleryImage.next(".copy--caption")).length) {
        item.title = $caption.html();
      } else if (($caption = $galleryImage.next("p").find(".caption")).length) {
        item.title = $caption.html();
      }

      if (youtubeID) {
        item.youtubeID = youtubeID;
        item.html = "<div class='pswp__youtube-player' id='" + youtubeID + "'></div>";
        item.title = null;
        item.src = null;
        item.msrc = null;
      } 

      items.push(item);
    });

    return items;
  }


  /**
   * Callback from photoswipe gallery close
   */
  onGalleryClose() {
    this._youtubeStop();
  }

  /**
   * Callback from photoswipe item change
   */
  onGalleryChange() {
    this._youtubePlay(this._gallery.currItem.youtubeID);
  }

  /**
   * Plays youtube movie if given proper movie ID
   */
  _youtubePlay(youtubeID) {
    if (youtubeID) {
      this._player = YouTubePlayer(youtubeID);
      this._player.loadVideoById(youtubeID);
      this._player.playVideo();
    } else {
      this._youtubeStop();
    }
  }

  /**
   * Stops youtube movie and destroys the player
   */
  _youtubeStop() {
    if (this._player) {
      this._player.destroy().then(() => {
        this._player = null;
      });
    }
  }

  /**
   * Gets youtube movie id from given youtube movie url
   */
  _youtubeID(url) {
    let regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,
        match = url.match(regExp);

    return match && match[2].length == 11 ? match[2] : null;
  }

  /**
   * Callback from photoswipe gallery close
   */
  onGalleryClose() {
    this._youtubeStop();
  }

  /**
   * Callback from photoswipe item change
   */
  onGalleryChange() {
    this._youtubePlay(this._gallery.currItem.youtubeID);
  }

  /**
   * Plays youtube movie if given proper movie ID
   */
  _youtubePlay(youtubeID) {
    if (youtubeID) {
      this._player = YouTubePlayer(youtubeID);
      this._player.loadVideoById(youtubeID);
      this._player.playVideo();
    } else {
      this._youtubeStop();
    }
  }

  /**
   * Stops youtube movie and destroys the player
   */
  _youtubeStop() {
    if (this._player) {
      this._player.destroy().then(() => {
        this._player = null;
      });
    }
  }

  /**
   * Gets youtube movie id from given youtube movie url
   */
  _youtubeID(url) {
    let regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,
        match = url.match(regExp);

    return match && match[2].length == 11 ? match[2] : null;
  }

  /**
   * Callback from clicking on a gallery image
   * @param  {Event}  event Event
   * @return {Object}       Returns an object to send data to GA for tracking
   */
  @track("gallery click");
  onGalleryClick(event) {
    event.preventDefault();

    let clickedListItem = event.currentTarget,
        index = this.$images.index(clickedListItem),
        src = $(clickedListItem).find("img").attr("src");

    if (index >= 0) {
      this.openPhotoSwipe(index);
    }

    return src;
  }

  /**
   * Open the photo gallery
   * @param  {[type]} index [description]
   * @return {[type]}       [description]
   */
  openPhotoSwipe(index = 0) {
    let items = this._parseThumbnailElements();

    let options = {
      galleryUID: this.$el.attr("data-pswp-uid"),
      getThumbBoundsFn: function(index) {
        let thumbnail = items[index].el, // find thumbnail
            pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
            rect = thumbnail.getBoundingClientRect();

        return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
      },
      history: false,
      counterEl: false,
      index
    };

    this._gallery = new PhotoSwipe( this.$pswp[0], PhotoSwipeUI_Default, items, options );
    this._gallery.listen("afterChange", this.onGalleryChange.bind(this));
    this._gallery.listen("close", this.onGalleryClose.bind(this));
    this._gallery.init();
  }
}