[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

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           * Initialize 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} True if the environment supports video, false otherwise.
  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} True if the video is paused, false otherwise.
 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           * @return {boolean} True if the handler can process a video, false otherwise. Default is false.
 221           */
 222          test: function() {
 223              return false;
 224          },
 225  
 226          /**
 227           * Trigger an event on the header container.
 228           *
 229           * @param {string} name Event name.
 230           */
 231          trigger: function( name ) {
 232              trigger( this.container, name );
 233          }
 234      };
 235  
 236      /**
 237       * Create a custom handler.
 238       *
 239       * @memberOf wp
 240       *
 241       * @param {Object} protoProps Properties to apply to the prototype.
 242       * @return {Function} Custom handler constructor.
 243       */
 244      BaseHandler.extend = function( protoProps ) {
 245          var prop;
 246  
 247          /**
 248           * Creates a custom handler instance.
 249           *
 250           * @return {CustomHandler} A custom handler instance, when called with new.
 251           */
 252  		function CustomHandler() {
 253              var result = BaseHandler.apply( this, arguments );
 254              return result;
 255          }
 256  
 257          CustomHandler.prototype = Object.create( BaseHandler.prototype );
 258          CustomHandler.prototype.constructor = CustomHandler;
 259  
 260          for ( prop in protoProps ) {
 261              CustomHandler.prototype[ prop ] = protoProps[ prop ];
 262          }
 263  
 264          return CustomHandler;
 265      };
 266  
 267      /**
 268       * Native video handler.
 269       *
 270       * @memberOf wp
 271       *
 272       * @class
 273       */
 274      NativeHandler = BaseHandler.extend(/** @lends wp.NativeHandler.prototype */{
 275          /**
 276           * Whether the native handler supports a video.
 277           *
 278           * @param {Object} settings Video settings.
 279           * @return {boolean} True if the native handler supports a video, false otherwise.
 280           */
 281          test: function( settings ) {
 282              var video = document.createElement( 'video' );
 283              return video.canPlayType( settings.mimeType );
 284          },
 285  
 286          /**
 287           * Set up a native video element.
 288           */
 289          ready: function() {
 290              var handler = this,
 291                  video = document.createElement( 'video' );
 292  
 293              video.id = 'wp-custom-header-video';
 294              video.autoplay = true;
 295              video.loop = true;
 296              video.muted = true;
 297              video.playsInline = true;
 298              video.width = this.settings.width;
 299              video.height = this.settings.height;
 300  
 301              video.addEventListener( 'play', function() {
 302                  handler.trigger( 'play' );
 303              });
 304  
 305              video.addEventListener( 'pause', function() {
 306                  handler.trigger( 'pause' );
 307              });
 308  
 309              video.addEventListener( 'canplay', function() {
 310                  handler.showControls();
 311              });
 312  
 313              this.video = video;
 314              handler.setVideo( video );
 315              video.src = this.settings.videoUrl;
 316          },
 317  
 318          /**
 319           * Whether the video is paused.
 320           *
 321           * @return {boolean} True if the video is paused, false otherwise.
 322           */
 323          isPaused: function() {
 324              return this.video.paused;
 325          },
 326  
 327          /**
 328           * Pause the video.
 329           */
 330          pause: function() {
 331              this.video.pause();
 332          },
 333  
 334          /**
 335           * Play the video.
 336           */
 337          play: function() {
 338              this.video.play();
 339          }
 340      });
 341  
 342      /**
 343       * YouTube video handler.
 344       *
 345       * @memberOf wp
 346       *
 347       * @class wp.YouTubeHandler
 348       */
 349      YouTubeHandler = BaseHandler.extend(/** @lends wp.YouTubeHandler.prototype */{
 350          /**
 351           * Whether the handler supports a video.
 352           *
 353           * @param {Object} settings Video settings.
 354           * @return {boolean} True if the handler supports a video, false otherwise.
 355           */
 356          test: function( settings ) {
 357              return 'video/x-youtube' === settings.mimeType;
 358          },
 359  
 360          /**
 361           * Set up a YouTube iframe.
 362           *
 363           * Loads the YouTube IFrame API if the 'YT' global doesn't exist.
 364           */
 365          ready: function() {
 366              var handler = this;
 367  
 368              if ( 'YT' in window ) {
 369                  YT.ready( handler.loadVideo.bind( handler ) );
 370              } else {
 371                  var tag = document.createElement( 'script' );
 372                  tag.src = 'https://www.youtube.com/iframe_api';
 373                  tag.onload = function () {
 374                      YT.ready( handler.loadVideo.bind( handler ) );
 375                  };
 376  
 377                  document.getElementsByTagName( 'head' )[0].appendChild( tag );
 378              }
 379          },
 380  
 381          /**
 382           * Load a YouTube video.
 383           */
 384          loadVideo: function() {
 385              var handler = this,
 386                  video = document.createElement( 'div' ),
 387                  // @link http://stackoverflow.com/a/27728417
 388                  VIDEO_ID_REGEX = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
 389  
 390              video.id = 'wp-custom-header-video';
 391              handler.setVideo( video );
 392  
 393              handler.player = new YT.Player( video, {
 394                  height: this.settings.height,
 395                  width: this.settings.width,
 396                  videoId: this.settings.videoUrl.match( VIDEO_ID_REGEX )[1],
 397                  events: {
 398                      onReady: function( e ) {
 399                          e.target.mute();
 400                          handler.showControls();
 401                      },
 402                      onStateChange: function( e ) {
 403                          if ( YT.PlayerState.PLAYING === e.data ) {
 404                              handler.trigger( 'play' );
 405                          } else if ( YT.PlayerState.PAUSED === e.data ) {
 406                              handler.trigger( 'pause' );
 407                          } else if ( YT.PlayerState.ENDED === e.data ) {
 408                              e.target.playVideo();
 409                          }
 410                      }
 411                  },
 412                  playerVars: {
 413                      autoplay: 1,
 414                      controls: 0,
 415                      disablekb: 1,
 416                      fs: 0,
 417                      iv_load_policy: 3,
 418                      loop: 1,
 419                      modestbranding: 1,
 420                      playsinline: 1,
 421                      rel: 0,
 422                      showinfo: 0
 423                  }
 424              });
 425          },
 426  
 427          /**
 428           * Whether the video is paused.
 429           *
 430           * @return {boolean} True if the video is paused, false otherwise.
 431           */
 432          isPaused: function() {
 433              return YT.PlayerState.PAUSED === this.player.getPlayerState();
 434          },
 435  
 436          /**
 437           * Pause the video.
 438           */
 439          pause: function() {
 440              this.player.pauseVideo();
 441          },
 442  
 443          /**
 444           * Play the video.
 445           */
 446          play: function() {
 447              this.player.playVideo();
 448          }
 449      });
 450  
 451      // Initialize the custom header when the DOM is ready.
 452      window.wp.customHeader = new CustomHeader();
 453      document.addEventListener( 'DOMContentLoaded', window.wp.customHeader.initialize.bind( window.wp.customHeader ), false );
 454  
 455      // Selective refresh support in the Customizer.
 456      if ( 'customize' in window.wp ) {
 457          window.wp.customize.selectiveRefresh.bind( 'render-partials-response', function( response ) {
 458              if ( 'custom_header_settings' in response ) {
 459                  settings = response.custom_header_settings;
 460              }
 461          });
 462  
 463          window.wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
 464              if ( 'custom_header' === placement.partial.id ) {
 465                  window.wp.customHeader.initialize();
 466              }
 467          });
 468      }
 469  
 470  })( window, window._wpCustomHeaderSettings || {} );


Generated : Tue Sep 29 08:20:35 2026 Cross-referenced by PHPXref