Manual Reference Source Test

src/loaders/ImageLoader.js

/**
*  @file ImageLoader.js
*  @author Liqueur de Toile <contact@liqueurdetoile.com>
*  @licence AGPL-3.0 {@link https://github.com/liqueurdetoile/beloader/blob/master/LICENSE}
*/

import AbstractLoader from 'core/AbstractLoader';

/**
*  If loaded async, the response will be added as a blob reference in src unless
*  an option `base64` set to `true` is provided. In that case, the image will
*  be parsed as a DataURI.
*
*  Image loader also accepts a `attributes` option to customize
*  resulting HtmlElement.
*
*  The resulting HtmlElement will not be inserted in DOM but provided
*  as a `image` property of the parent QueueItem. The property will be available
*  as soon as loader will be available to permit DOM insertion at
*  creation. It can be retrieved with the `loaderReady` promise exposed
*  by QueueItem.
*
*  @version 1.0.0
*  @since 1.0.0
*  @author Liqueur de Toile <contact@liqueurdetoile.com>
*  @extends {AbstractLoader}
*
*  @example
*  var loader = new Beloader();
*
*  // Sync mode with display only when loaded
*  var img = loader.fetch('img', {
*    url: 'http://myserver.com/image.jpg',
*    async: false,
*    attributes : {
*      alt: 'My image',
*      width: '100px',
*      height: '100px'
*    }
*  }).then(item => {
*    document.body.appendChild(item.image);
*  });
*
*  // Async mode with display only when loaded (as a blob object)
*  var img = loader.fetch('img', {
*    url: 'http://myserver.com/image.jpg',
*    attributes : {
*      alt: 'My image',
*      width: '100px',
*      height: '100px'
*    }
*  }).then(item => {
*    document.body.appendChild(item.image);
*  });
*
*  // Async mode with display only when loaded (as a DataURI string)
*  var img = loader.fetch('img', {
*    url: 'http://myserver.com/image.jpg',
*    base64: true,
*    attributes : {
*      alt: 'My image',
*      width: '100px',
*      height: '100px'
*    }
*  }).then(item => {
*    document.body.appendChild(item.image);
*  });
*/

export default class ImageLoader extends AbstractLoader {
  /**
  *  @version 1.0.0
  *  @since 1.0.0
  *  @author Liqueur de Toile <contact@liqueurdetoile.com>
  *
  *  @param {QueueItem} parent Calling QueueItem
  *  @param {DotObjectArray} options Options for the loader
  *  @param {string} options.url  URL of the asset
  *  @param {boolean} [options.base64=false]  If set to `true` and loaded async, the asset
  *  will be parsed as a base64 data string. Otherwise, it will be parsed as binary blob
  *  @param {Object} [options.attributes] Attributes for the resulting HTML node
  *  @throws {TypeError}  if `options.url` is not defined
  */
  constructor(parent, options) {
    super(parent, options);
    if (!options.has('url')) throw new TypeError('Beloader : image url must be defined');
    options.define('base64', false);
    /**
    *  Underlying node for insertion
    *  @type {HTMLElement}
    */
    this._node = this.node;
    this.parent.image = this.node;
  }

  /**
  *  Getter that generates HTMLElement to contain image (sync or async)
  *
  *  @version 1.0.0
  *  @since 1.0.0
  *  @author Liqueur de Toile <contact@liqueurdetoile.com>
  *  @type {HTMLElement} HTMLElement
  */
  get node() {
    if (typeof this._node === 'undefined') {
      this._node = document.createElement('img');
      this.options.forEach(function (val, attr) {
        this._node.setAttribute(attr, val);
      }.bind(this), 'attributes', null, false);
    }

    return this._node;
  }

  /**
  *  Load image
  *
  *  @version 1.0.0
  *  @since 1.0.0
  *  @author Liqueur de Toile <contact@liqueurdetoile.com>
  *
  *  @returns {Promise} Loading promise
  */
  sync() {
    this.node.src = this.options.data.url;
    return super.sync();
  }

  /**
  *  Event hook to add specific Blob request headers to
  *  XMLHttpRequest instance
  *
  *  @version 1.0.0
  *  @since 1.0.0
  *  @author Liqueur de Toile <contact@liqueurdetoile.com>
  */
  _loadstart() {
    if (this.xhr) this.xhr.responseType = 'blob';
  }

  /**
  *  Load image binary (blob) or dataUri (base64) and update src attribute
  *
  *  @version 1.0.0
  *  @since 1.0.0
  *  @author Liqueur de Toile <contact@liqueurdetoile.com>
  *
  *  @returns {Promise} Loading promise
  */
  async() {
    const _this = this;

    return new Promise((resolve, reject) => {
      super.async().then(response => {
        if (_this.options.data.base64) {
          // Decode binary as base64
          let reader = new window.FileReader();

          reader.readAsDataURL(response);
          reader.onload = () => {
            _this.node.src = reader.result;
            resolve();
          };
          reader.onerror = () => {
            reject(reader.error);
          };
        } else { // Decode as binary blob
          let url = window.URL || window.webkitURL;

          try {
            _this.node.src = url.createObjectURL(response);
            resolve();
          } catch (e) {
            reject(e);
          }
        }
      });
    });
  }
}

export {ImageLoader};