[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/js/ -> wp-custom-header.js (source)

   1  /**
   2   * @output wp-includes/js/wp-custom-header.js
   3   */
   4  
   5  /* global YT */
   6  (function( window, settings ) {
   7  
   8      var NativeHandler, YouTubeHandler;
   9  
  10      /** @namespace wp */
  11      window.wp = window.wp || {};
  12  
  13      // Fail gracefully in unsupported browsers.
  14      if ( ! ( 'addEventListener' in window ) ) {
  15          return;
  16      }
  17  
  18      /**
  19       * Trigger an event.
  20       *
  21       * @param {Element} target HTML element to dispatch the event on.
  22       * @param {string} name Event name.
  23       */
  24  	function trigger( target, name ) {
  25          var evt;
  26  
  27          if ( 'function' === typeof window.Event ) {
  28              evt = new Event( name );
  29          } else {
  30              evt = document.createEvent( 'Event' );
  31              evt.initEvent( name, true, true );
  32          }
  33  
  34          target.dispatchEvent( evt );
  35      }
  36  
  37      /**
  38       * Create a custom header instance.
  39       *
  40       * @memberOf wp
  41       *
  42       * @class
  43       */
  44  	function CustomHeader() {
  45          this.handlers = {
  46              nativeVideo: new NativeHandler(),
  47              youtube: new YouTubeHandler()
  48          };
  49      }
  50  
  51      CustomHeader.prototype = {
  52          /**
  53           * Initalize the custom header.
  54           *
  55           * If the environment supports video, loops through registered handlers
  56           * until one is found that can handle the video.
  57           */
  58          initialize: function() {
  59              if ( this.supportsVideo() ) {
  60                  for ( var id in this.handlers ) {
  61                      var handler = this.handlers[ id ];
  62  
  63                      if ( 'test' in handler && handler.test( settings ) ) {
  64                          this.activeHandler = handler.initialize.call( handler, settings );
  65  
  66                          // Dispatch custom event when the video is loaded.
  67                          trigger( document, 'wp-custom-header-video-loaded' );
  68                          break;
  69                      }
  70                  }
  71              }
  72          },
  73  
  74          /**
  75           * Determines if the current environment supports video.
  76           *
  77           * Themes and plugins can override this method to change the criteria.
  78           *
  79           * @return {boolean}
  80           */
  81          supportsVideo: function() {
  82              // Don't load video on small screens. @todo: consider bandwidth and other factors.
  83              if ( window.innerWidth < settings.minWidth || window.innerHeight < settings.minHeight ) {
  84                  return false;
  85              }
  86  
  87              return true;
  88          },
  89  
  90          /**
  91           * Base handler for custom handlers to extend.
  92           *
  93           * @type {BaseHandler}
  94           */
  95          BaseVideoHandler: BaseHandler
  96      };
  97  
  98      /**
  99       * Create a video handler instance.
 100       *
 101       * @memberOf wp
 102       *
 103       * @class
 104       */
 105  	function BaseHandler() {}
 106  
 107      BaseHandler.prototype = {
 108          /**
 109           * Initialize the video handler.
 110           *
 111           * @param {object} settings Video settings.
 112           */
 113          initialize: function( settings ) {
 114              var handler = this,
 115                  button = document.createElement( 'button' );
 116  
 117              this.settings = settings;
 118              this.container = document.getElementById( 'wp-custom-header' );
 119              this.button = button;
 120  
 121              button.setAttribute( 'type', 'button' );
 122              button.setAttribute( 'id', 'wp-custom-header-video-button' );
 123              button.setAttribute( 'class', 'wp-custom-header-video-button wp-custom-header-video-play' );
 124              button.innerHTML = settings.l10n.play;
 125  
 126              // Toggle video playback when the button is clicked.
 127              button.addEventListener( 'click', function() {
 128                  if ( handler.isPaused() ) {
 129                      handler.play();
 130                  } else {
 131                      handler.pause();
 132                  }
 133              });
 134  
 135              // Update the button class and text when the video state changes.
 136              this.container.addEventListener( 'play', function() {
 137                  button.className = 'wp-custom-header-video-button wp-custom-header-video-play';
 138                  button.innerHTML = settings.l10n.pause;
 139                  if ( 'a11y' in window.wp ) {
 140                      window.wp.a11y.speak( settings.l10n.playSpeak);
 141                  }
 142              });
 143  
 144              this.container.addEventListener( 'pause', function() {
 145                  button.className = 'wp-custom-header-video-button wp-custom-header-video-pause';
 146                  button.innerHTML = settings.l10n.play;
 147                  if ( 'a11y' in window.wp ) {
 148                      window.wp.a11y.speak( settings.l10n.pauseSpeak);
 149                  }
 150              });
 151  
 152              this.ready();
 153          },
 154  
 155          /**
 156           * Ready method called after a handler is initialized.
 157           *
 158           * @abstract
 159           */
 160          ready: function() {},
 161  
 162          /**
 163           * Whether the video is paused.
 164           *
 165           * @abstract
 166           * @return {boolean}
 167           */
 168          isPaused: function() {},
 169  
 170          /**
 171           * Pause the video.
 172           *
 173           * @abstract
 174           */
 175          pause: function() {},
 176  
 177          /**
 178           * Play the video.
 179           *
 180           * @abstract
 181           */
 182          play: function() {},
 183  
 184          /**
 185           * Append a video node to the header container.
 186           *
 187           * @param {Element} node HTML element.
 188           */
 189          setVideo: function( node ) {
 190              var editShortcutNode,
 191                  editShortcut = this.container.getElementsByClassName( 'customize-partial-edit-shortcut' );
 192  
 193              if ( editShortcut.length ) {
 194                  editShortcutNode = this.container.removeChild( editShortcut[0] );
 195              }
 196  
 197              this.container.innerHTML = '';
 198              this.container.appendChild( node );
 199  
 200              if ( editShortcutNode ) {
 201                  this.container.appendChild( editShortcutNode );
 202              }
 203          },
 204  
 205          /**
 206           * Show the video controls.
 207           *
 208           * Appends a play/pause button to header container.
 209           */
 210          showControls: function() {
 211              if ( ! this.container.contains( this.button ) ) {
 212                  this.container.appendChild( this.button );
 213              }
 214          },
 215  
 216          /**
 217           * Whether the handler can process a video.
 218           *
 219           * @abstract
 220           * @param {object} settings Video settings.
 221           * @return {boolean}
 222           */
 223          test: function() {
 224              return false;
 225          },
 226  
 227          /**
 228           * Trigger an event on the header container.
 229           *
 230           * @param {string} name Event name.
 231           */
 232          trigger: function( name ) {
 233              trigger( this.container, name );
 234          }
 235      };
 236  
 237      /**
 238       * Create a custom handler.
 239       *
 240       * @memberOf wp
 241       *
 242       * @param {object} protoProps Properties to apply to the prototype.
 243       * @return CustomHandler The subclass.
 244       */
 245      BaseHandler.extend = function( protoProps ) {
 246          var prop;
 247  
 248  		function CustomHandler() {
 249              var result = BaseHandler.apply( this, arguments );
 250              return result;
 251          }
 252  
 253          CustomHandler.prototype = Object.create( BaseHandler.prototype );
 254          CustomHandler.prototype.constructor = CustomHandler;
 255  
 256          for ( prop in protoProps ) {
 257              CustomHandler.prototype[ prop ] = protoProps[ prop ];
 258          }
 259  
 260          return CustomHandler;
 261      };
 262  
 263      /**
 264       * Native video handler.
 265       *
 266       * @memberOf wp
 267       *
 268       * @class
 269       */
 270      NativeHandler = BaseHandler.extend(/** @lends wp.NativeHandler.prototype */{
 271          /**
 272           * Whether the native handler supports a video.
 273           *
 274           * @param {object} settings Video settings.
 275           * @return {boolean}
 276           */
 277          test: function( settings ) {
 278              var video = document.createElement( 'video' );
 279              return video.canPlayType( settings.mimeType );
 280          },
 281  
 282          /**
 283           * Set up a native video element.
 284           */
 285          ready: function() {
 286              var handler = this,
 287                  video = document.createElement( 'video' );
 288  
 289              video.id = 'wp-custom-header-video';
 290              video.autoplay = 'autoplay';
 291              video.loop = 'loop';
 292              video.muted = 'muted';
 293              video.width = this.settings.width;
 294              video.height = this.settings.height;
 295  
 296              video.addEventListener( 'play', function() {
 297                  handler.trigger( 'play' );
 298              });
 299  
 300              video.addEventListener( 'pause', function() {
 301                  handler.trigger( 'pause' );
 302              });
 303  
 304              video.addEventListener( 'canplay', function() {
 305                  handler.showControls();
 306              });
 307  
 308              this.video = video;
 309              handler.setVideo( video );
 310              video.src = this.settings.videoUrl;
 311          },
 312  
 313          /**
 314           * Whether the video is paused.
 315           *
 316           * @return {boolean}
 317           */
 318          isPaused: function() {
 319              return this.video.paused;
 320          },
 321  
 322          /**
 323           * Pause the video.
 324           */
 325          pause: function() {
 326              this.video.pause();
 327          },
 328  
 329          /**
 330           * Play the video.
 331           */
 332          play: function() {
 333              this.video.play();
 334          }
 335      });
 336  
 337      /**
 338       * YouTube video handler.
 339       *
 340       * @memberOf wp
 341       *
 342       * @class wp.YouTubeHandler
 343       */
 344      YouTubeHandler = BaseHandler.extend(/** @lends wp.YouTubeHandler.prototype */{
 345          /**
 346           * Whether the handler supports a video.
 347           *
 348           * @param {object} settings Video settings.
 349           * @return {boolean}
 350           */
 351          test: function( settings ) {
 352              return 'video/x-youtube' === settings.mimeType;
 353          },
 354  
 355          /**
 356           * Set up a YouTube iframe.
 357           *
 358           * Loads the YouTube IFrame API if the 'YT' global doesn't exist.
 359           */
 360          ready: function() {
 361              var handler = this;
 362  
 363              if ( 'YT' in window ) {
 364                  YT.ready( handler.loadVideo.bind( handler ) );
 365              } else {
 366                  var tag = document.createElement( 'script' );
 367                  tag.src = 'https://www.youtube.com/iframe_api';
 368                  tag.onload = function () {
 369                      YT.ready( handler.loadVideo.bind( handler ) );
 370                  };
 371  
 372                  document.getElementsByTagName( 'head' )[0].appendChild( tag );
 373              }
 374          },
 375  
 376          /**
 377           * Load a YouTube video.
 378           */
 379          loadVideo: function() {
 380              var handler = this,
 381                  video = document.createElement( 'div' ),
 382                  // @link http://stackoverflow.com/a/27728417
 383                  VIDEO_ID_REGEX = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
 384  
 385              video.id = 'wp-custom-header-video';
 386              handler.setVideo( video );
 387  
 388              handler.player = new YT.Player( video, {
 389                  height: this.settings.height,
 390                  width: this.settings.width,
 391                  videoId: this.settings.videoUrl.match( VIDEO_ID_REGEX )[1],
 392                  events: {
 393                      onReady: function( e ) {
 394                          e.target.mute();
 395                          handler.showControls();
 396                      },
 397                      onStateChange: function( e ) {
 398                          if ( YT.PlayerState.PLAYING === e.data ) {
 399                              handler.trigger( 'play' );
 400                          } else if ( YT.PlayerState.PAUSED === e.data ) {
 401                              handler.trigger( 'pause' );
 402                          } else if ( YT.PlayerState.ENDED === e.data ) {
 403                              e.target.playVideo();
 404                          }
 405                      }
 406                  },
 407                  playerVars: {
 408                      autoplay: 1,
 409                      controls: 0,
 410                      disablekb: 1,
 411                      fs: 0,
 412                      iv_load_policy: 3,
 413                      loop: 1,
 414                      modestbranding: 1,
 415                      playsinline: 1,
 416                      rel: 0,
 417                      showinfo: 0
 418                  }
 419              });
 420          },
 421  
 422          /**
 423           * Whether the video is paused.
 424           *
 425           * @return {boolean}
 426           */
 427          isPaused: function() {
 428              return YT.PlayerState.PAUSED === this.player.getPlayerState();
 429          },
 430  
 431          /**
 432           * Pause the video.
 433           */
 434          pause: function() {
 435              this.player.pauseVideo();
 436          },
 437  
 438          /**
 439           * Play the video.
 440           */
 441          play: function() {
 442              this.player.playVideo();
 443          }
 444      });
 445  
 446      // Initialize the custom header when the DOM is ready.
 447      window.wp.customHeader = new CustomHeader();
 448      document.addEventListener( 'DOMContentLoaded', window.wp.customHeader.initialize.bind( window.wp.customHeader ), false );
 449  
 450      // Selective refresh support in the Customizer.
 451      if ( 'customize' in window.wp ) {
 452          window.wp.customize.selectiveRefresh.bind( 'render-partials-response', function( response ) {
 453              if ( 'custom_header_settings' in response ) {
 454                  settings = response.custom_header_settings;
 455              }
 456          });
 457  
 458          window.wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
 459              if ( 'custom_header' === placement.partial.id ) {
 460                  window.wp.customHeader.initialize();
 461              }
 462          });
 463      }
 464  
 465  })( window, window._wpCustomHeaderSettings || {} );


Generated: Sat Nov 23 20:47:33 2019 Cross-referenced by PHPXref 0.7