home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / wp-custom-header.js < prev    next >
Encoding:
JavaScript  |  2017-09-08  |  10.1 KB  |  462 lines

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