blazy-8.x-2.x-dev/js/src/components/blazy.media.js

js/src/components/blazy.media.js
/**
 * @file
 * Provides Media module integration.
 */

(function ($, Drupal, _win, _doc) {

  'use strict';

  var MD = 'media';
  var ID = 'b-' + MD;
  var ID_ONCE = ID;
  var IFRAME = 'iframe';
  var MD_PLAYER = MD + '--player';
  var S_MOUNTED = 'is-' + ID;
  var S_PLAYER = '.' + MD_PLAYER;
  var S_ELEMENT = S_PLAYER + ':not(.' + S_MOUNTED + ')';
  var ICON = MD + '__icon';
  var S_PLAY = '.' + ICON + '--play';
  var S_CLOSE = '.' + ICON + '--close';
  var C_IS_PLAYING = 'is-playing';
  var C_IS_BODY_PLAYING = 'is-b-player-playing';
  var DATA = 'data-';
  var DATA_IFRAME_TITLE = DATA + IFRAME + '-title';
  var DATA_URL = DATA + 'b-url';
  var C_MD_ELEMENT = MD + '__element';
  var B_INSTAGRAM = 'b-instagram';
  var C_HIDDEN = 'visually-hidden';
  var FN_MULTIMEDIA = $.multimedia || false;

  /**
   * Blazy media utility functions.
   *
   * @param {HTMLElement} el
   *   The media player HTML element.
   */
  function process(el) {
    var $el = $(el);
    var iframe = $el.find(IFRAME);
    var btn = $el.find(S_PLAY);

    // Media player toggler is disabled, just display iframe.
    if (!$.isElm(btn)) {
      return;
    }

    var url = $.attr(btn, DATA_URL);
    var title = $.attr(btn, DATA_IFRAME_TITLE);
    var instagram = $el.hasClass(B_INSTAGRAM);
    var newIframe;

    if (url && $.sanitizer.isDangerous('src', url)) {
      return;
    }

    /**
     * Play the media.
     *
     * @param {Event} e
     *   The event triggered by a `click` event.
     *
     * @return {bool|mixed}
     *   Return false if url is not available.
     */
    function play(e) {
      e.preventDefault();

      // oEmbed/ Soundcloud needs internet, fails on disconnected local.
      if (!url) {
        return false;
      }

      // Reset any (local) video/ audio to avoid multiple elements from playing.
      if (FN_MULTIMEDIA) {
        FN_MULTIMEDIA.pause();
      }

      var target = this;
      var sPlayable = '.' + C_IS_PLAYING + ':not(.' + B_INSTAGRAM + ')';
      var playing = $.find(_doc, sPlayable);
      var player = target.parentNode;

      // Remove other playing remote videos.
      if ($.isElm(playing)) {
        var played = $.find(_doc, sPlayable + ' ' + IFRAME);
        // Remove the previous iframe.
        $.remove(played);
        playing.className = playing.className.replace(/(\S+)playing/, '');
      }

      $.addClass(player, C_IS_PLAYING);

      if (!instagram) {
        playNow(e);
      }
    }

    /**
     * Play the media.
     *
     * @param {Event} e
     *   The event triggered by a `click` event.
     */
    function playNow(e) {
      var target = e.target;
      var player = $.closest(target, S_PLAYER);
      var iframe = $.find(player, IFRAME);

      url = $.attr(target, DATA_URL);
      title = $.attr(target, DATA_IFRAME_TITLE);

      // Remove the existing iframe on the current clicked iframe.
      $.remove(iframe);

      // DOM ready fix, for slow iframe removal.
      _win.setTimeout(function () {
        // Cache iframe for the potential repeating clicks.
        if (!newIframe) {
          newIframe = $.create(IFRAME, C_MD_ELEMENT);

          // Saving another clicks for nested iframes.
          $.attr(newIframe, {
            src: url,
            allow: 'autoplay; fullscreen',
            title: Drupal.checkPlain(title)
          });
        }

        // Appends the iframe.
        player.appendChild(newIframe);

        $.addClass(_doc.body, C_IS_BODY_PLAYING);

        // Be sure to detach on your destroy method, or Drupal..detach:
        // $.off('blazy:mediaPlaying', onPlaying);
        // After calling:
        // $.on('blazy:mediaPlaying', onPlaying);
        $.trigger(_win, 'blazy:mediaPlaying', {
          player: player
        });
      });
    }

    /**
     * Close the media.
     *
     * @param {Event} e
     *   The event triggered by a `click` event.
     *
     * @return {bool|mixed}
     *   Return false if instagram API.
     */
    function stop(e) {
      e.preventDefault();

      var target = this;

      if (instagram) {
        $.addClass(target, C_HIDDEN);
        return false;
      }

      var player = target.parentNode;

      var iframe = $.find(player, IFRAME);
      if (player.className.match(C_IS_PLAYING)) {
        player.className = player.className.replace(/(\S+)playing/, '');
      }

      $.remove(iframe);
      $.removeClass(_doc.body, C_IS_BODY_PLAYING);

      // Be sure to detach on your destroy method, or Drupal..detach:
      // $.off('blazy:mediaStopped', onStopped);
      // After calling:
      // $.on('blazy:mediaStopped', onStopped);
      $.trigger(_win, 'blazy:mediaStopped', {
        player: player
      });
    }

    /**
     * Reacts on `blazy:done` event sprcific for Instagram HTML content.
     *
     * @param {Event} e
     *   The event triggered by a `blazy:done` event.
     */
    /*
    function onDone(e) {
      var target = e.target;
      var player = $.hasClass(target, MD_PLAYER) ? target : $.closest(target, S_PLAYER);
      var btn = $.find(player, S_PLAY);

      // Autoload instagram player on being lazy loaded.
      if ($.isElm(btn)) {
        btn.click();
      }
    }
     */

    // Remove iframe if any to avoid browser requesting them till clicked.
    $.remove(iframe);

    // Plays the media player.
    $el.on('click.' + ID, S_PLAY, play);

    // Closes the video.
    $el.on('click.' + ID, S_CLOSE, stop);

    var checkWidth = function () {
      var ws = $.windowSize();
      var data = $.parse(el.dataset.bMp);
      var min = $.matchMedia('1024px') && !data.fs ? 15 : 0;
      var width = data.owidth;
      var height = data.oheight;
      var as = $.image.scale(width, height, ws.width - min, ws.height - min);
      var p = el.parentNode;
      width = as.width > width ? width : as.width;

      if ($.hasClass(p, 'media-wrapper')) {
        p.style.width = width + 'px';
        if (data.ratio !== data.oratio) {
          el.style.padding = 'padding-bottom: ' + data.ratio + '%';
        }
      }
    };

    $.on(_win, 'resize.' + ID + ' orientationchange.' + ID, $.debounce(checkWidth, 210));

    // Listens to blazy:done event to auto-display instagram feeds.
    // if (instagram) {
    // $el.on('blazy:done', onDone);
    // }
    $.removeClass(_doc.body, C_IS_BODY_PLAYING);
    $el.addClass(S_MOUNTED);
  }

  /**
   * Theme function for a dynamic inline video.
   *
   * @param {Object} settings
   *   An object containing the link element which triggers the lightbox.
   *   This link must have [data-b-media]|[data-media] attribute containing
   *   video metadata. [data-media] is deprecated for [data-b-media].
   *
   * @return {HTMLElement}
   *   Returns a HTMLElement object.
   */
  Drupal.theme.blazyMedia = function (settings) {
    // PhotoSwipe5 has element, PhotoSwipe4 el, etc.
    var el = settings.el || settings.element;
    var $el = $(el);
    var alt = $.image.alt(el);
    var data = $.parse($.attr(el, 'data-b-' + MD));
    var provider = data.provider;
    var token = data.token;
    var width = $.toInt(data.width, 640);
    var height = $.toInt(data.height, 360);
    var pad = $.image.ratio(data);
    var imgUrl = $el.attr('data-box-url');
    var href = el.href;
    var oembedUrl = $el.attr('data-oembed-url', href, true);
    var defClass = MD + '__element';
    var imgClass = settings.imgClass ?
      defClass + ' ' + settings.imgClass :
      defClass;
    var idClass = data.id ? ' ' + MD + '--' + data.id : '';
    var player = data.playable || data.boxType === 'iframe' ? ' ' + MD_PLAYER : '';
    var ariaClose = Drupal.t('Stop and close the video');
    var ariaPlay = Drupal.t('Load and play the video');
    var bProvider = '';
    var bToken = '';
    var ws = $.windowSize();
    var fs = data.fs || false;
    var min = $.matchMedia('1024px') && !fs ? 15 : 0;
    var as = $.image.scale(width, height, ws.width - min, ws.height - min);
    var mp;
    var oheight = height;
    var owidth = width;
    var html = '';

    width = as.width > width ? width : as.width;
    height = as.height > height ? height : as.height;

    var obj = {
      width: width,
      height: height,
      ratio: ((height / width) * 100).toFixed(2),
      owidth: owidth,
      oheight: oheight,
      oratio: pad,
      fs: fs
    };

    mp = Drupal.checkPlain(JSON.stringify(obj));

    if (imgUrl) {
      html += '<img src="$imgUrl" class="$imgClass" alt="$alt" loading="lazy" decoding="async" />';
    }

    if (player) {
      if (provider) {
        bProvider = ' data-b-provider="' + provider + '"';
      }
      if (token) {
        bToken = ' data-b-token="' + token + '"';
      }

      html += '<span class="$icon $icon--close" aria-label="$ariaClose"></span>';
      html += '<span class="$icon $icon--play" data-b-url="$oembed" data-iframe-title="$alt" aria-label="$ariaPlay"$bProvider$bToken></span>';
    }

    html = '<div class="$md $idClass $md--switch $player $md--ratio $md--ratio--fluid" aria-live="polite" style="padding-bottom: $pad%" data-b-mp="$mp">' + html + '</div>';

    if (!settings.unwrap) {
      html = '<div class="$wrapper $wrapper--inline" style="width: $widthpx">' + html + '</div>';
    }

    return $.template(html, {
      md: MD,
      icon: ICON,
      ariaClose: Drupal.checkPlain(ariaClose),
      ariaPlay: Drupal.checkPlain(ariaPlay),
      bProvider: bProvider,
      bToken: bToken,
      idClass: idClass,
      player: player,
      pad: pad,
      mp: mp,
      imgUrl: imgUrl,
      imgClass: imgClass,
      alt: alt,
      oembed: oembedUrl,
      width: width,
      wrapper: MD + '-wrapper'
    });
  };

  /**
   * Attaches Blazy media behavior to HTML element.
   *
   * @type {Drupal~behavior}
   */
  Drupal.behaviors.blazyMedia = {
    attach: function (context) {
      $.once(process, ID_ONCE, S_ELEMENT, context);
    },
    detach: function (context, setting, trigger) {
      if (trigger === 'unload') {
        $.removeClass(_doc.body, C_IS_BODY_PLAYING);
        $.once.removeSafely(ID_ONCE, S_ELEMENT, context);
      }
    }
  };

})(dBlazy, Drupal, this, this.document);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc