WordPress.org

Make WordPress Core

Changeset 41797


Ignore:
Timestamp:
10/09/2017 04:03:35 PM (8 months ago)
Author:
westonruter
Message:

Customize: Eliminate use of customize-loader in core so Customizer is opened consistently in top window.

  • Open the door for future browser history feature in #28536, which is currently not feasible when customize-loader is used.
  • Remove customizer-loader from being used on admin screens for Dashboard, Themes, non-shiny theme install/update.
  • Keep the customize-loader functionality available for plugins, for the time being. It may become deprecated.
  • Ensure return param in customizer links in Themes screen update to reflect search updated by pushState.
  • Persist return when reloading Customizer due to theme switch, autosave restoration, or changeset trashing.
  • Use location.replace() instead of changing location.href when trashing.
  • Hide theme browser while Themes screen is loading when there is a search to prevent flash of unfiltered themes.
  • Use throttling instead of debouncing when searching themes to ensure that screen is updated immediately on page load.
  • Fix encoding and decoding of search param between URL and search field.
  • Add support for dismissing autosaves when closing customize-loader, when it is used by plugins.
  • Skip sending changeset UUID to customize-loader for population in browser location if changeset branching is not enabled.

See #28536.
Fixes #40254.

Location:
trunk/src
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/themes.css

    r41667 r41797  
    77  16.1 - Manage Themes
    88------------------------------------------------------------------------------*/
     9
     10body.js .theme-browser.search-loading {
     11    display: none;
     12}
    913
    1014.theme-browser .themes {
  • trunk/src/wp-admin/includes/class-theme-installer-skin.php

    r41161 r41797  
    6565
    6666        if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    67             $install_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
     67            $customize_url = add_query_arg(
     68                array(
     69                    'theme' => urlencode( $stylesheet ),
     70                    'return' => urlencode( admin_url( 'web' === $this->type ? 'theme-install.php' : 'themes.php' ) ),
     71                ),
     72                admin_url( 'customize.php' )
     73            );
     74            $install_actions['preview'] = '<a href="' . esc_url( $customize_url ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
    6875        }
    6976        $install_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink"><span aria-hidden="true">' . __( 'Activate' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Activate &#8220;%s&#8221;' ), $name ) . '</span></a>';
  • trunk/src/wp-admin/includes/class-theme-upgrader-skin.php

    r41161 r41797  
    5050            $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
    5151
     52            $customize_url = add_query_arg(
     53                array(
     54                    'theme' => urlencode( $stylesheet ),
     55                    'return' => urlencode( admin_url( 'themes.php' ) ),
     56                ),
     57                admin_url( 'customize.php' )
     58            );
    5259            if ( get_stylesheet() == $stylesheet ) {
    5360                if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    54                     $update_actions['preview']  = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Customize' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Customize &#8220;%s&#8221;' ), $name ) . '</span></a>';
     61                    $update_actions['preview']  = '<a href="' . esc_url( $customize_url ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Customize' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Customize &#8220;%s&#8221;' ), $name ) . '</span></a>';
    5562                }
    5663            } elseif ( current_user_can( 'switch_themes' ) ) {
    5764                if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    58                     $update_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
     65                    $update_actions['preview'] = '<a href="' . esc_url( $customize_url ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
    5966                }
    6067                $update_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink"><span aria-hidden="true">' . __( 'Activate' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Activate &#8220;%s&#8221;' ), $name ) . '</span></a>';
  • trunk/src/wp-admin/index.php

    r40776 r41797  
    1717wp_enqueue_script( 'dashboard' );
    1818
    19 if ( current_user_can( 'edit_theme_options' ) )
    20     wp_enqueue_script( 'customize-loader' );
    2119if ( current_user_can( 'install_plugins' ) ) {
    2220    wp_enqueue_script( 'plugin-install' );
  • trunk/src/wp-admin/js/customize-controls.js

    r41788 r41797  
    107107         * @since 4.9.0
    108108         *
    109          * @param {string|wp.customize.Notification} - Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied.
     109         * @param {string|wp.customize.Notification} notification - Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied.
    110110         * @param {wp.customize.Notification} [notificationObject] - Notification to add when first argument is the code string.
    111111         * @returns {wp.customize.Notification} Added notification (or existing instance if it was already added).
     
    30153015                {
    30163016                    theme: themeId,
    3017                     changeset_uuid: api.settings.changeset.uuid
     3017                    changeset_uuid: api.settings.changeset.uuid,
     3018                    'return': api.settings.url['return']
    30183019                }
    30193020            );
     
    30453046                    deferred.resolve();
    30463047                    $( window ).off( 'beforeunload.customize-confirm' );
    3047                     window.location.href = urlParser.href; // @todo Use location.replace()?
     3048                    location.replace( urlParser.href );
    30483049                } );
    30493050                request.fail( function() {
     
    69596960                            api.settings.changeset.uuid = response.next_changeset_uuid;
    69606961                            api.state( 'changesetStatus' ).set( '' );
    6961                             parent.send( 'changeset-uuid', api.settings.changeset.uuid );
     6962                            if ( api.settings.changeset.branching ) {
     6963                                parent.send( 'changeset-uuid', api.settings.changeset.uuid );
     6964                            }
    69626965                            api.previewer.send( 'changeset-uuid', api.settings.changeset.uuid );
    69636966                        }
     
    69906993                            api.state( 'changesetStatus' ).set( '' );
    69916994                            api.settings.changeset.uuid = response.next_changeset_uuid;
    6992                             parent.send( 'changeset-uuid', api.settings.changeset.uuid );
     6995                            if ( api.settings.changeset.branching ) {
     6996                                parent.send( 'changeset-uuid', api.settings.changeset.uuid );
     6997                            }
    69936998                        }
    69946999
     
    70667071                    queryParams = api.utils.parseQueryString( urlParser.search.substr( 1 ) );
    70677072                    delete queryParams.changeset_uuid;
     7073                    queryParams['return'] = api.settings.url['return'];
    70687074                    urlParser.search = $.param( queryParams );
    70697075                    location.replace( urlParser.href );
     
    74197425                    queryParams.customize_autosaved = 'on';
    74207426                }
     7427                queryParams['return'] = api.settings.url['return'];
    74217428                urlParser.search = $.param( queryParams );
    74227429                return urlParser.href;
     
    79167923            api.bind( 'change', startPromptingBeforeUnload );
    79177924
    7918             closeBtn.on( 'click.customize-controls-close', function( event ) {
     7925            function requestClose() {
    79197926                var clearedToClose = $.Deferred();
    7920                 event.preventDefault();
    7921 
    7922                 /*
    7923                  * The isInsideIframe condition is because Customizer is not able to use a confirm()
    7924                  * since customize-loader.js will also use one. So autosave restorations are disabled
    7925                  * when customize-loader.js is used.
    7926                  */
    7927                 if ( isInsideIframe || isCleanState() ) {
     7927                if ( isCleanState() ) {
    79287928                    clearedToClose.resolve();
    79297929                } else if ( confirm( api.l10n.saveAlert ) ) {
     
    79557955                    clearedToClose.reject();
    79567956                }
    7957 
    7958                 clearedToClose.done( function() {
    7959                     $( window ).off( 'beforeunload.customize-confirm' );
    7960                     if ( isInsideIframe ) {
    7961                         parent.send( 'close' );
    7962                     } else {
     7957                return clearedToClose.promise();
     7958            }
     7959
     7960            parent.bind( 'confirm-close', function() {
     7961                requestClose().done( function() {
     7962                    parent.send( 'confirmed-close', true );
     7963                } ).fail( function() {
     7964                    parent.send( 'confirmed-close', false );
     7965                } );
     7966            } );
     7967
     7968            closeBtn.on( 'click.customize-controls-close', function( event ) {
     7969                event.preventDefault();
     7970                if ( isInsideIframe ) {
     7971                    parent.send( 'close' ); // See confirm-close logic above.
     7972                } else {
     7973                    requestClose().done( function() {
     7974                        $( window ).off( 'beforeunload.customize-confirm' );
    79637975                        window.location.href = closeBtn.prop( 'href' );
    7964                     }
    7965                 } );
     7976                    } );
     7977                }
    79667978            });
    79677979        })();
     
    79797991        });
    79807992
    7981         parent.send( 'changeset-uuid', api.settings.changeset.uuid );
     7993        if ( api.settings.changeset.branching ) {
     7994            parent.send( 'changeset-uuid', api.settings.changeset.uuid );
     7995        }
    79827996
    79837997        // Initialize the connection with the parent frame.
  • trunk/src/wp-admin/js/theme.js

    r41683 r41797  
    7777        // Render search form.
    7878        this.search();
     79
     80        this.$el.removeClass( 'search-loading' );
    7981
    8082        // Render and append
     
    13461348        }
    13471349
    1348         /**
    1349          * Since doSearch is debounced, it will only run when user input comes to a rest
    1350          */
     1350        // Note that doSearch is throttled.
    13511351        this.doSearch( event );
    13521352    },
    13531353
    13541354    // Runs a search on the theme collection.
    1355     doSearch: _.debounce( function( event ) {
     1355    doSearch: _.throttle( function( event ) {
    13561356        var options = {};
    13571357
    1358         this.collection.doSearch( event.target.value );
     1358        this.collection.doSearch( event.target.value.replace( /\+/g, ' ' ) );
    13591359
    13601360        // if search is initiated and key is not return
     
    13771377
    13781378        if ( event.target.value ) {
    1379             url = themes.router.baseUrl( themes.router.searchPath + event.target.value );
     1379            url = themes.router.baseUrl( themes.router.searchPath + encodeURIComponent( event.target.value ) );
    13801380        }
    13811381
     
    13851385    }
    13861386});
     1387
     1388/**
     1389 * Navigate router.
     1390 *
     1391 * @since 4.9.0
     1392 *
     1393 * @param {string} url - URL to navigate to.
     1394 * @param {object} state - State.
     1395 * @returns {void}
     1396 */
     1397function navigateRouter( url, state ) {
     1398    var router = this;
     1399    if ( Backbone.history._hasPushState ) {
     1400        Backbone.Router.prototype.navigate.call( router, url, state );
     1401    }
     1402}
    13871403
    13881404// Sets up the routes events for relevant url queries
     
    14061422
    14071423    search: function( query ) {
    1408         $( '.wp-filter-search' ).val( query );
     1424        $( '.wp-filter-search' ).val( query.replace( /\+/g, ' ' ) );
    14091425    },
    14101426
     
    14131429    },
    14141430
    1415     navigate: function() {
    1416         if ( Backbone.history._hasPushState ) {
    1417             Backbone.Router.prototype.navigate.apply( this, arguments );
    1418         }
    1419     }
     1431    navigate: navigateRouter
    14201432
    14211433});
     
    15091521    },
    15101522
    1511     doSearch: _.debounce( function( value ) {
     1523    doSearch: _.throttle( function( value ) {
    15121524        var request = {};
    15131525
     
    15521564
    15531565        // Set route
    1554         themes.router.navigate( themes.router.baseUrl( themes.router.searchPath + value ), { replace: true } );
     1566        themes.router.navigate( themes.router.baseUrl( themes.router.searchPath + encodeURIComponent( value ) ), { replace: true } );
    15551567    }, 500 )
    15561568});
     
    18881900
    18891901    search: function( query ) {
    1890         $( '.wp-filter-search' ).val( query );
    1891     },
    1892 
    1893     navigate: function() {
    1894         if ( Backbone.history._hasPushState ) {
    1895             Backbone.Router.prototype.navigate.apply( this, arguments );
    1896         }
    1897     }
     1902        $( '.wp-filter-search' ).val( query.replace( /\+/g, ' ' ) );
     1903    },
     1904
     1905    navigate: navigateRouter
    18981906});
    18991907
     
    20032011        themes.Run.init();
    20042012    }
     2013
     2014    // Update the return param just in time.
     2015    $( document.body ).on( 'click', '.load-customize', function() {
     2016        var link = $( this ), urlParser = document.createElement( 'a' );
     2017        urlParser.href = link.prop( 'href' );
     2018        urlParser.search = $.param( _.extend(
     2019            wp.customize.utils.parseQueryString( urlParser.search.substr( 1 ) ),
     2020            {
     2021                'return': window.location.href
     2022            }
     2023        ) );
     2024        link.prop( 'href', urlParser.href );
     2025    });
    20052026
    20062027    $( '.broken-themes .delete-theme' ).on( 'click', function() {
  • trunk/src/wp-admin/themes.php

    r41658 r41797  
    147147wp_enqueue_script( 'theme' );
    148148wp_enqueue_script( 'updates' );
    149 wp_enqueue_script( 'customize-loader' );
    150149
    151150require_once( ABSPATH . 'wp-admin/admin-header.php' );
     
    154153<div class="wrap">
    155154    <h1 class="wp-heading-inline"><?php esc_html_e( 'Themes' ); ?>
    156         <span class="title-count theme-count"><?php echo count( $themes ); ?></span>
     155        <span class="title-count theme-count"><?php echo ! empty( $_GET['search'] ) ? __( '&hellip;' ) : count( $themes ); ?></span>
    157156    </h1>
    158157
     
    235234?>
    236235
    237 <div class="theme-browser">
     236<?php
     237$class_name = 'theme-browser';
     238if ( ! empty( $_GET['search'] ) ) {
     239    $class_name .= ' search-loading';
     240}
     241?>
     242<div class="<?php echo esc_attr( $class_name ); ?>">
    238243    <div class="themes wp-clearfix">
    239244
  • trunk/src/wp-admin/update.php

    r41289 r41797  
    174174        check_admin_referer('upgrade-theme_' . $theme);
    175175
    176         wp_enqueue_script( 'customize-loader' );
    177176        wp_enqueue_script( 'updates' );
    178177
     
    224223        $api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
    225224
    226         if ( is_wp_error($api) )
    227             wp_die($api);
    228 
    229         wp_enqueue_script( 'customize-loader' );
     225        if ( is_wp_error( $api ) ) {
     226            wp_die( $api );
     227        }
    230228
    231229        $title = __('Install Themes');
     
    253251
    254252        $file_upload = new File_Upload_Upgrader('themezip', 'package');
    255 
    256         wp_enqueue_script( 'customize-loader' );
    257253
    258254        $title = __('Upload Theme');
  • trunk/src/wp-includes/class-wp-customize-manager.php

    r41793 r41797  
    42374237            'url'      => array(
    42384238                'preview'       => esc_url_raw( $this->get_preview_url() ),
     4239                'return'        => esc_url_raw( $this->get_return_url() ),
    42394240                'parent'        => esc_url_raw( admin_url() ),
    42404241                'activated'     => esc_url_raw( home_url( '/' ) ),
  • trunk/src/wp-includes/js/customize-loader.js

    r41351 r41797  
    1 /* global _wpCustomizeLoaderSettings, confirm */
     1/* global _wpCustomizeLoaderSettings */
    22/**
    33 * Expose a public API that allows the customizer to be
     
    209209         */
    210210        close: function() {
    211             if ( ! this.active ) {
     211            var self = this, onConfirmClose;
     212            if ( ! self.active ) {
    212213                return;
    213214            }
    214215
    215             // Display AYS dialog if Customizer is dirty
    216             if ( ! this.saved() && ! confirm( Loader.settings.l10n.saveAlert ) ) {
    217                 // Go forward since Customizer is exited by history.back()
    218                 history.forward();
    219                 return;
    220             }
    221 
    222             this.active = false;
    223 
    224             this.trigger( 'close' );
    225 
    226             // Restore document title prior to opening the Live Preview
    227             if ( this.originalDocumentTitle ) {
    228                 document.title = this.originalDocumentTitle;
    229             }
     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' );
    230235        },
    231236
  • trunk/src/wp-includes/script-loader.php

    r41791 r41797  
    726726        $scripts->add( 'custom-html-widgets', "/wp-admin/js/widgets/custom-html-widgets$suffix.js", array( 'code-editor', 'jquery', 'backbone', 'wp-util', 'jquery-ui-core', 'wp-a11y' ) );
    727727
    728         $scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'wp-backbone', 'wp-a11y' ), false, 1 );
     728        $scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'wp-backbone', 'wp-a11y', 'customize-base' ), false, 1 );
    729729
    730730        $scripts->add( 'inline-edit-post', "/wp-admin/js/inline-edit-post$suffix.js", array( 'jquery', 'tags-suggest', 'wp-a11y' ), false, 1 );
Note: See TracChangeset for help on using the changeset viewer.