| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 || {} );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Tue Sep 29 08:20:35 2026 | Cross-referenced by PHPXref |