WordPress.org

Make WordPress Core

Changeset 29025


Ignore:
Timestamp:
07/08/2014 05:03:48 PM (5 years ago)
Author:
helen
Message:

Prompt the user before leaving the Customizer if they have unsaved changes. props westonruter. fixes #25439.

Location:
trunk/src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/customize-controls.js

    r28269 r29025  
    916916        var previewer, parent, topFocus,
    917917            body = $( document.body ),
    918             overlay = body.children('.wp-full-overlay');
     918            overlay = body.children( '.wp-full-overlay' ),
     919            backBtn = $( '.back' ),
     920            saveBtn = $( '#save' );
    919921
    920922        // Prevent the form from saving when enter is pressed on an input or select element.
     
    10411043
    10421044            state.bind( 'change', function() {
    1043                 var save = $('#save'),
    1044                     back = $('.back');
    1045 
    10461045                if ( ! activated() ) {
    1047                     save.val( api.l10n.activate ).prop( 'disabled', false );
    1048                     back.text( api.l10n.cancel );
     1046                    saveBtn.val( api.l10n.activate ).prop( 'disabled', false );
     1047                    backBtn.text( api.l10n.cancel );
    10491048
    10501049                } else if ( saved() ) {
    1051                     save.val( api.l10n.saved ).prop( 'disabled', true );
    1052                     back.text( api.l10n.close );
     1050                    saveBtn.val( api.l10n.saved ).prop( 'disabled', true );
     1051                    backBtn.text( api.l10n.close );
    10531052
    10541053                } else {
    1055                     save.val( api.l10n.save ).prop( 'disabled', false );
    1056                     back.text( api.l10n.cancel );
     1054                    saveBtn.val( api.l10n.save ).prop( 'disabled', false );
     1055                    backBtn.text( api.l10n.cancel );
    10571056                }
    10581057            });
     
    10821081
    10831082        // Button bindings.
    1084         $('#save').click( function( event ) {
     1083        saveBtn.click( function( event ) {
    10851084            previewer.save();
    10861085            event.preventDefault();
     
    10931092        });
    10941093
    1095         $('.back').keydown( function( event ) {
     1094        backBtn.keydown( function( event ) {
    10961095            if ( 9 === event.which ) // tab
    10971096                return;
     
    11231122        // Send any clicks to the 'Return' link to the parent page.
    11241123        parent.bind( 'back', function() {
    1125             $('.back').on( 'click.back', function( event ) {
     1124            backBtn.on( 'click.back', function( event ) {
    11261125                event.preventDefault();
    11271126                parent.send( 'close' );
     
    11291128        });
    11301129
     1130        // Prompt user with AYS dialog if leaving the Customizer with unsaved changes
     1131        $( window ).on( 'beforeunload', function () {
     1132            if ( ! api.state( 'saved' )() ) {
     1133                return api.l10n.saveAlert;
     1134            }
     1135        } );
     1136
    11311137        // Pass events through to the parent.
    1132         api.bind( 'saved', function() {
    1133             parent.send( 'saved' );
    1134         });
     1138        $.each( [ 'saved', 'change' ], function ( i, event ) {
     1139            api.bind( event, function() {
     1140                parent.send( event );
     1141            });
     1142        } );
    11351143
    11361144        // When activated, let the loader handle redirecting the page.
     
    11991207
    12001208        // Make sure left column gets focus
    1201         topFocus = $('.back');
     1209        topFocus = backBtn;
    12021210        topFocus.focus();
    12031211        setTimeout(function () {
  • trunk/src/wp-includes/js/customize-loader.js

    r26194 r29025  
    1 /* global _wpCustomizeLoaderSettings */
     1/* global _wpCustomizeLoaderSettings, confirm */
    22window.wp = window.wp || {};
    33
     
    3737
    3838            // Add navigation listeners.
    39             if ( $.support.history )
     39            if ( $.support.history ) {
    4040                this.window.on( 'popstate', Loader.popstate );
     41            }
    4142
    4243            if ( $.support.hashchange ) {
     
    4849        popstate: function( e ) {
    4950            var state = e.originalEvent.state;
    50             if ( state && state.customize )
     51            if ( state && state.customize ) {
    5152                Loader.open( state.customize );
    52             else if ( Loader.active )
     53            } else if ( Loader.active ) {
    5354                Loader.close();
     55            }
    5456        },
    5557
     
    5759            var hash = window.location.toString().split('#')[1];
    5860
    59             if ( hash && 0 === hash.indexOf( 'wp_customize=on' ) )
     61            if ( hash && 0 === hash.indexOf( 'wp_customize=on' ) ) {
    6062                Loader.open( Loader.settings.url + '?' + hash );
    61 
    62             if ( ! hash && ! $.support.history )
     63            }
     64
     65            if ( ! hash && ! $.support.history ){
    6366                Loader.close();
     67            }
     68        },
     69
     70        beforeunload: function () {
     71            if ( ! Loader.saved() ) {
     72                return Loader.settings.l10n.saveAlert;
     73            }
    6474        },
    6575
    6676        open: function( src ) {
    67             var hash;
    68 
    69             if ( this.active )
    70                 return;
     77
     78            if ( this.active ) {
     79                return;
     80            }
    7181
    7282            // Load the full page on mobile devices.
    73             if ( Loader.settings.browser.mobile )
     83            if ( Loader.settings.browser.mobile ) {
    7484                return window.location = src;
     85            }
    7586
    7687            this.active = true;
    7788            this.body.addClass('customize-loading');
     89
     90            // Dirty state of customizer in iframe
     91            this.saved = new api.Value( true );
    7892
    7993            this.iframe = $( '<iframe />', { src: src }).appendTo( this.element );
     
    93107
    94108            this.messenger.bind( 'close', function() {
    95                 if ( $.support.history )
     109                if ( $.support.history ) {
    96110                    history.back();
    97                 else if ( $.support.hashchange )
     111                } else if ( $.support.hashchange ) {
    98112                    window.location.hash = '';
    99                 else
     113                } else {
    100114                    Loader.close();
    101             });
     115                }
     116            } );
     117
     118            // Prompt AYS dialog when navigating away
     119            $( window ).on( 'beforeunload', this.beforeunload );
    102120
    103121            this.messenger.bind( 'activated', function( location ) {
    104                 if ( location )
     122                if ( location ) {
    105123                    window.location = location;
    106             });
    107 
    108             hash = src.split('?')[1];
     124                }
     125            });
     126
     127            this.messenger.bind( 'saved', function () {
     128                Loader.saved( true );
     129            } );
     130            this.messenger.bind( 'change', function () {
     131                Loader.saved( false );
     132            } );
     133
     134            this.pushState( src );
     135
     136            this.trigger( 'open' );
     137        },
     138
     139        pushState: function ( src ) {
     140            var hash;
    109141
    110142            // Ensure we don't call pushState if the user hit the forward button.
    111             if ( $.support.history && window.location.href !== src )
     143            if ( $.support.history && window.location.href !== src ) {
    112144                history.pushState( { customize: src }, '', src );
    113             else if ( ! $.support.history && $.support.hashchange && hash )
     145            } else if ( ! $.support.history && $.support.hashchange && hash ) {
     146                hash = src.split( '?' )[1];
    114147                window.location.hash = 'wp_customize=on&' + hash;
    115 
    116             this.trigger( 'open' );
     148            }
    117149        },
    118150
     
    122154
    123155        close: function() {
    124             if ( ! this.active )
    125                 return;
     156            if ( ! this.active ) {
     157                return;
     158            }
     159
     160            // Display AYS dialog if customizer is dirty
     161            if ( ! this.saved() && ! confirm( Loader.settings.l10n.saveAlert ) ) {
     162                // Go forward since Customizer is exited by history.back()
     163                history.forward();
     164                return;
     165            }
     166
    126167            this.active = false;
    127168
     
    129170
    130171            // Return focus to link that was originally clicked.
    131             if ( this.link )
     172            if ( this.link ) {
    132173                this.link.focus();
     174            }
    133175        },
    134176
     
    138180            Loader.iframe    = null;
    139181            Loader.messenger = null;
     182            Loader.saved     = null;
    140183            Loader.body.removeClass( 'customize-active full-overlay-active' ).removeClass( 'customize-loading' );
     184            $( window ).off( 'beforeunload', Loader.beforeunload );
    141185        },
    142186
  • trunk/src/wp-includes/script-loader.php

    r29020 r29025  
    383383        'activate'  => __( 'Save &amp; Activate' ),
    384384        'save'      => __( 'Save &amp; Publish' ),
     385        'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
    385386        'saved'     => __( 'Saved' ),
    386387        'cancel'    => __( 'Cancel' ),
  • trunk/src/wp-includes/theme.php

    r28999 r29025  
    18751875        'isCrossDomain' => $cross_domain,
    18761876        'browser'       => $browser,
     1877        'l10n'          => array(
     1878            'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
     1879        ),
    18771880    );
    18781881
Note: See TracChangeset for help on using the changeset viewer.