home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / customize-loader.js < prev    next >
Encoding:
JavaScript  |  2017-10-09  |  7.7 KB  |  287 lines

  1. /* global _wpCustomizeLoaderSettings */
  2. /**
  3.  * Expose a public API that allows the customizer to be
  4.  * loaded on any page.
  5.  *
  6.  * @namespace wp
  7.  */
  8. window.wp = window.wp || {};
  9.  
  10. (function( exports, $ ){
  11.     var api = wp.customize,
  12.         Loader;
  13.  
  14.     $.extend( $.support, {
  15.         history: !! ( window.history && history.pushState ),
  16.         hashchange: ('onhashchange' in window) && (document.documentMode === undefined || document.documentMode > 7)
  17.     });
  18.  
  19.     /**
  20.      * Allows the Customizer to be overlayed on any page.
  21.      *
  22.      * By default, any element in the body with the load-customize class will open
  23.      * an iframe overlay with the URL specified.
  24.      *
  25.      *     e.g. <a class="load-customize" href="<?php echo wp_customize_url(); ?>">Open Customizer</a>
  26.      *
  27.      * @memberOf wp.customize
  28.      *
  29.      * @class
  30.      * @augments wp.customize.Events
  31.      */
  32.     Loader = $.extend( {}, api.Events,/** @lends wp.customize.Loader.prototype */{
  33.         /**
  34.          * Setup the Loader; triggered on document#ready.
  35.          */
  36.         initialize: function() {
  37.             this.body = $( document.body );
  38.  
  39.             // Ensure the loader is supported.
  40.             // Check for settings, postMessage support, and whether we require CORS support.
  41.             if ( ! Loader.settings || ! $.support.postMessage || ( ! $.support.cors && Loader.settings.isCrossDomain ) ) {
  42.                 return;
  43.             }
  44.  
  45.             this.window  = $( window );
  46.             this.element = $( '<div id="customize-container" />' ).appendTo( this.body );
  47.  
  48.             // Bind events for opening and closing the overlay.
  49.             this.bind( 'open', this.overlay.show );
  50.             this.bind( 'close', this.overlay.hide );
  51.  
  52.             // Any element in the body with the `load-customize` class opens
  53.             // the Customizer.
  54.             $('#wpbody').on( 'click', '.load-customize', function( event ) {
  55.                 event.preventDefault();
  56.  
  57.                 // Store a reference to the link that opened the Customizer.
  58.                 Loader.link = $(this);
  59.                 // Load the theme.
  60.                 Loader.open( Loader.link.attr('href') );
  61.             });
  62.  
  63.             // Add navigation listeners.
  64.             if ( $.support.history ) {
  65.                 this.window.on( 'popstate', Loader.popstate );
  66.             }
  67.  
  68.             if ( $.support.hashchange ) {
  69.                 this.window.on( 'hashchange', Loader.hashchange );
  70.                 this.window.triggerHandler( 'hashchange' );
  71.             }
  72.         },
  73.  
  74.         popstate: function( e ) {
  75.             var state = e.originalEvent.state;
  76.             if ( state && state.customize ) {
  77.                 Loader.open( state.customize );
  78.             } else if ( Loader.active ) {
  79.                 Loader.close();
  80.             }
  81.         },
  82.  
  83.         hashchange: function() {
  84.             var hash = window.location.toString().split('#')[1];
  85.  
  86.             if ( hash && 0 === hash.indexOf( 'wp_customize=on' ) ) {
  87.                 Loader.open( Loader.settings.url + '?' + hash );
  88.             }
  89.  
  90.             if ( ! hash && ! $.support.history ) {
  91.                 Loader.close();
  92.             }
  93.         },
  94.  
  95.         beforeunload: function () {
  96.             if ( ! Loader.saved() ) {
  97.                 return Loader.settings.l10n.saveAlert;
  98.             }
  99.         },
  100.  
  101.         /**
  102.          * Open the Customizer overlay for a specific URL.
  103.          *
  104.          * @param  string src URL to load in the Customizer.
  105.          */
  106.         open: function( src ) {
  107.  
  108.             if ( this.active ) {
  109.                 return;
  110.             }
  111.  
  112.             // Load the full page on mobile devices.
  113.             if ( Loader.settings.browser.mobile ) {
  114.                 return window.location = src;
  115.             }
  116.  
  117.             // Store the document title prior to opening the Live Preview
  118.             this.originalDocumentTitle = document.title;
  119.  
  120.             this.active = true;
  121.             this.body.addClass('customize-loading');
  122.  
  123.             /*
  124.              * Track the dirtiness state (whether the drafted changes have been published)
  125.              * of the Customizer in the iframe. This is used to decide whether to display
  126.              * an AYS alert if the user tries to close the window before saving changes.
  127.              */
  128.             this.saved = new api.Value( true );
  129.  
  130.             this.iframe = $( '<iframe />', { 'src': src, 'title': Loader.settings.l10n.mainIframeTitle } ).appendTo( this.element );
  131.             this.iframe.one( 'load', this.loaded );
  132.  
  133.             // Create a postMessage connection with the iframe.
  134.             this.messenger = new api.Messenger({
  135.                 url: src,
  136.                 channel: 'loader',
  137.                 targetWindow: this.iframe[0].contentWindow
  138.             });
  139.  
  140.             // Expose the changeset UUID on the parent window's URL so that the customized state can survive a refresh.
  141.             if ( history.replaceState ) {
  142.                 this.messenger.bind( 'changeset-uuid', function( changesetUuid ) {
  143.                     var urlParser = document.createElement( 'a' );
  144.                     urlParser.href = location.href;
  145.                     urlParser.search = $.param( _.extend(
  146.                         api.utils.parseQueryString( urlParser.search.substr( 1 ) ),
  147.                         { changeset_uuid: changesetUuid }
  148.                     ) );
  149.                     history.replaceState( { customize: urlParser.href }, '', urlParser.href );
  150.                 } );
  151.             }
  152.  
  153.             // Wait for the connection from the iframe before sending any postMessage events.
  154.             this.messenger.bind( 'ready', function() {
  155.                 Loader.messenger.send( 'back' );
  156.             });
  157.  
  158.             this.messenger.bind( 'close', function() {
  159.                 if ( $.support.history ) {
  160.                     history.back();
  161.                 } else if ( $.support.hashchange ) {
  162.                     window.location.hash = '';
  163.                 } else {
  164.                     Loader.close();
  165.                 }
  166.             });
  167.  
  168.             // Prompt AYS dialog when navigating away
  169.             $( window ).on( 'beforeunload', this.beforeunload );
  170.  
  171.             this.messenger.bind( 'saved', function () {
  172.                 Loader.saved( true );
  173.             } );
  174.             this.messenger.bind( 'change', function () {
  175.                 Loader.saved( false );
  176.             } );
  177.  
  178.             this.messenger.bind( 'title', function( newTitle ){
  179.                 window.document.title = newTitle;
  180.             });
  181.  
  182.             this.pushState( src );
  183.  
  184.             this.trigger( 'open' );
  185.         },
  186.  
  187.         pushState: function ( src ) {
  188.             var hash = src.split( '?' )[1];
  189.  
  190.             // Ensure we don't call pushState if the user hit the forward button.
  191.             if ( $.support.history && window.location.href !== src ) {
  192.                 history.pushState( { customize: src }, '', src );
  193.             } else if ( ! $.support.history && $.support.hashchange && hash ) {
  194.                 window.location.hash = 'wp_customize=on&' + hash;
  195.             }
  196.  
  197.             this.trigger( 'open' );
  198.         },
  199.  
  200.         /**
  201.          * Callback after the Customizer has been opened.
  202.          */
  203.         opened: function() {
  204.             Loader.body.addClass( 'customize-active full-overlay-active' ).attr( 'aria-busy', 'true' );
  205.         },
  206.  
  207.         /**
  208.          * Close the Customizer overlay.
  209.          */
  210.         close: function() {
  211.             var self = this, onConfirmClose;
  212.             if ( ! self.active ) {
  213.                 return;
  214.             }
  215.  
  216.             onConfirmClose = function( confirmed ) {
  217.                 if ( confirmed ) {
  218.                     self.active = false;
  219.                     self.trigger( 'close' );
  220.  
  221.                     // Restore document title prior to opening the Live Preview
  222.                     if ( self.originalDocumentTitle ) {
  223.                         document.title = self.originalDocumentTitle;
  224.                     }
  225.                 } else {
  226.  
  227.                     // Go forward since Customizer is exited by history.back()
  228.                     history.forward();
  229.                 }
  230.                 self.messenger.unbind( 'confirmed-close', onConfirmClose );
  231.             };
  232.             self.messenger.bind( 'confirmed-close', onConfirmClose );
  233.  
  234.             Loader.messenger.send( 'confirm-close' );
  235.         },
  236.  
  237.         /**
  238.          * Callback after the Customizer has been closed.
  239.          */
  240.         closed: function() {
  241.             Loader.iframe.remove();
  242.             Loader.messenger.destroy();
  243.             Loader.iframe    = null;
  244.             Loader.messenger = null;
  245.             Loader.saved     = null;
  246.             Loader.body.removeClass( 'customize-active full-overlay-active' ).removeClass( 'customize-loading' );
  247.             $( window ).off( 'beforeunload', Loader.beforeunload );
  248.             /*
  249.              * Return focus to the link that opened the Customizer overlay after
  250.              * the body element visibility is restored.
  251.              */
  252.             if ( Loader.link ) {
  253.                 Loader.link.focus();
  254.             }
  255.         },
  256.  
  257.         /**
  258.          * Callback for the `load` event on the Customizer iframe.
  259.          */
  260.         loaded: function() {
  261.             Loader.body.removeClass( 'customize-loading' ).attr( 'aria-busy', 'false' );
  262.         },
  263.  
  264.         /**
  265.          * Overlay hide/show utility methods.
  266.          */
  267.         overlay: {
  268.             show: function() {
  269.                 this.element.fadeIn( 200, Loader.opened );
  270.             },
  271.  
  272.             hide: function() {
  273.                 this.element.fadeOut( 200, Loader.closed );
  274.             }
  275.         }
  276.     });
  277.  
  278.     // Bootstrap the Loader on document#ready.
  279.     $( function() {
  280.         Loader.settings = _wpCustomizeLoaderSettings;
  281.         Loader.initialize();
  282.     });
  283.  
  284.     // Expose the API publicly on window.wp.customize.Loader
  285.     api.Loader = Loader;
  286. })( wp, jQuery );
  287.