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