[ 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}
  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 = true;
 291              video.loop = true;
 292              video.muted = true;
 293              video.playsInline = true;
 294              video.width = this.settings.width;
 295              video.height = this.settings.height;
 296  
 297              video.addEventListener( 'play', function() {
 298                  handler.trigger( 'play' );
 299              });
 300  
 301              video.addEventListener( 'pause', function() {
 302                  handler.trigger( 'pause' );
 303              });
 304  
 305              video.addEventListener( 'canplay', function() {
 306                  handler.showControls();
 307              });
 308  
 309              this.video = video;
 310              handler.setVideo( video );
 311              video.src = this.settings.videoUrl;
 312          },
 313  
 314          /**
 315           * Whether the video is paused.
 316           *
 317           * @return {boolean}
 318           */
 319          isPaused: function() {
 320              return this.video.paused;
 321          },
 322  
 323          /**
 324           * Pause the video.
 325           */
 326          pause: function() {
 327              this.video.pause();
 328          },
 329  
 330          /**
 331           * Play the video.
 332           */
 333          play: function() {
 334              this.video.play();
 335          }
 336      });
 337  
 338      /**
 339       * YouTube video handler.
 340       *
 341       * @memberOf wp
 342       *
 343       * @class wp.YouTubeHandler
 344       */
 345      YouTubeHandler = BaseHandler.extend(/** @lends wp.YouTubeHandler.prototype */{
 346          /**
 347           * Whether the handler supports a video.
 348           *
 349           * @param {Object} settings Video settings.
 350           * @return {boolean}
 351           */
 352          test: function( settings ) {
 353              return 'video/x-youtube' === settings.mimeType;
 354          },
 355  
 356          /**
 357           * Set up a YouTube iframe.
 358           *
 359           * Loads the YouTube IFrame API if the 'YT' global doesn't exist.
 360           */
 361          ready: function() {
 362              var handler = this;
 363  
 364              if ( 'YT' in window ) {
 365                  YT.ready( handler.loadVideo.bind( handler ) );
 366              } else {
 367                  var tag = document.createElement( 'script' );
 368                  tag.src = 'https://www.youtube.com/iframe_api';
 369                  tag.onload = function () {
 370                      YT.ready( handler.loadVideo.bind( handler ) );
 371                  };
 372  
 373                  document.getElementsByTagName( 'head' )[0].appendChild( tag );
 374              }
 375          },
 376  
 377          /**
 378           * Load a YouTube video.
 379           */
 380          loadVideo: function() {
 381              var handler = this,
 382                  video = document.createElement( 'div' ),
 383                  // @link http://stackoverflow.com/a/27728417
 384                  VIDEO_ID_REGEX = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
 385  
 386              video.id = 'wp-custom-header-video';
 387              handler.setVideo( video );
 388  
 389              handler.player = new YT.Player( video, {
 390                  height: this.settings.height,
 391                  width: this.settings.width,
 392                  videoId: this.settings.videoUrl.match( VIDEO_ID_REGEX )[1],
 393                  events: {
 394                      onReady: function( e ) {
 395                          e.target.mute();
 396                          handler.showControls();
 397                      },
 398                      onStateChange: function( e ) {
 399                          if ( YT.PlayerState.PLAYING === e.data ) {
 400                              handler.trigger( 'play' );
 401                          } else if ( YT.PlayerState.PAUSED === e.data ) {
 402                              handler.trigger( 'pause' );
 403                          } else if ( YT.PlayerState.ENDED === e.data ) {
 404                              e.target.playVideo();
 405                          }
 406                      }
 407                  },
 408                  playerVars: {
 409                      autoplay: 1,
 410                      controls: 0,
 411                      disablekb: 1,
 412                      fs: 0,
 413                      iv_load_policy: 3,
 414                      loop: 1,
 415                      modestbranding: 1,
 416                      playsinline: 1,
 417                      rel: 0,
 418                      showinfo: 0
 419                  }
 420              });
 421          },
 422  
 423          /**
 424           * Whether the video is paused.
 425           *
 426           * @return {boolean}
 427           */
 428          isPaused: function() {
 429              return YT.PlayerState.PAUSED === this.player.getPlayerState();
 430          },
 431  
 432          /**
 433           * Pause the video.
 434           */
 435          pause: function() {
 436              this.player.pauseVideo();
 437          },
 438  
 439          /**
 440           * Play the video.
 441           */
 442          play: function() {
 443              this.player.playVideo();
 444          }
 445      });
 446  
 447      // Initialize the custom header when the DOM is ready.
 448      window.wp.customHeader = new CustomHeader();
 449      document.addEventListener( 'DOMContentLoaded', window.wp.customHeader.initialize.bind( window.wp.customHeader ), false );
 450  
 451      // Selective refresh support in the Customizer.
 452      if ( 'customize' in window.wp ) {
 453          window.wp.customize.selectiveRefresh.bind( 'render-partials-response', function( response ) {
 454              if ( 'custom_header_settings' in response ) {
 455                  settings = response.custom_header_settings;
 456              }
 457          });
 458  
 459          window.wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
 460              if ( 'custom_header' === placement.partial.id ) {
 461                  window.wp.customHeader.initialize();
 462              }
 463          });
 464      }
 465  
 466  })( window, window._wpCustomHeaderSettings || {} );


Generated : Thu Nov 21 08:20:01 2024 Cross-referenced by PHPXref