Home Reference Source Test Repository

src/components/article_body/article_body.js

import { Component } from "../../core/bane";
import $ from "jquery";
import ImageGallery from "../image_gallery";
import PoiCallout from "../poi_callout";
import moment from "moment";
import matchMedia from "../../core/utils/matchMedia";
import rizzo from "../../rizzo"; 

/**
 * Enhances the body of articles with a gallery and more
 */
export default class ArticleBodyComponent extends Component {
  initialize(options) {
    this.imageContainerSelector = ".stack__article__image-container";
    this.poiData = options.poiData;

    this.loadImages().then(() => {
      this.gallery = new ImageGallery({
        el: this.$el
      });
    });

    if (this.poiData) {
      matchMedia("(min-width: 1200px)", (query) => {
        if (query.matches) {
          this.loadPoiCallout(this.poiData);
        } else {
          if (typeof this.poiCallout !== "undefined") {
            this.poiCallout.destroy();
          }
        }
      });
    }

    this.formatDate();
  }

  /**
   * Loads all the images in the body of the article
   * @return {Promise} A promise for when all of the images have loaded
   */
  loadImages() {
    let promises = [];

    this.$el.find(this.imageContainerSelector).each((index, el) => {
      let $img = $(el).find("img"),
          $a = $(el).find("a").eq(0),
          $span = $(el).find("span"),
          src = $($img).attr("src");

      let promise = this.loadImage(src).then((image) => {
        if (!$a.length) {
          $img.wrap(`<a class="copy--body__link" href="${src}" data-size="${image.width}x${image.height}" />`);
        } else {
          $a.attr("data-size", `${image.width}x${image.height}`);
        }

        if(image.width > 1000 && $img.hasClass("is-landscape")) {
          $(el).addClass("is-wide");
        }

        $(el).addClass("is-visible");

        if (!$span.length) {
          $(el).contents().filter(function() {
            return this.nodeType === 3 && $.trim(this.nodeValue).length;
          }).wrap(`<span class="copy--caption" />`);
        }
      });

      promises.push(promise);
    });

    return Promise.all(promises).catch((err) => {
      rizzo.logger.error(err);
    });
  }

  /**
   * Preload an image
   * @param  {String} url Url of the image to load
   * @return {Promise} A promise for when the image loads
   */
  loadImage(url) {
    let image = new Image();

    return new Promise((resolve, reject) => {
      image.src = url;
      image.onload = function() {
        resolve(image);
      };
      image.onerror = function() {
        reject(url);
      };

      if (!url) {
        reject(url);
      }
    });
  }

  /**
   * Format the post date with moment.js
   */
  formatDate() {
    let $footer = this.$el.siblings(".js-article-footer"),
        date = $footer.find("time").attr("datetime"),
        formattedDate = moment(date).format("MMMM YYYY");

    $footer
      .find("time").html(formattedDate)
      .closest(".js-article-post-date").removeProp("hidden");
  }

  /**
   * Creates a new instance of the POI callout
   * @param {Object} data POI data
   */
  loadPoiCallout(data) {
    this.poiCallout = new PoiCallout({
      el: this.$el,
      pois: data
    });
  }
}