[ Index ] |
PHP Cross Reference of WordPress |
[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} 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 || {} );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Mar 8 01:00:04 2021 | Cross-referenced by PHPXref 0.7.1 |