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