Customize: Update server-sent setting validation notifications as changes are entered.

Send back setting validities with full refreshes and selective refreshes so that invalid settings can have notifications displayed immediately before attempting save, and so that these notifications can be cleared as soon as the input is corrected.

* Splits out JS logic for listing controls into separate methods  `wp.customize.Setting.prototype.findControls()` and `wp.customize.findControlsForSettings()`.
* Adds a `setting` property to the `data` on notifications added to controls that are synced from their settings.
* Adds `selective-refresh-setting-validities` message sent from preview to pane.
* Changes `WP_Customize_Manager::validate_setting_values()` to return when settings are valid as well as invalid.
* Adds `WP_Customize_Manager::prepare_setting_validity_for_js()`.
* Add setting validities to data exported to JS in Customizer Preview and in selective refresh responses.

Fixes #36944.

Built from https://develop.svn.wordpress.org/trunk@37700


git-svn-id: http://core.svn.wordpress.org/trunk@37666 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Weston Ruter 2016-06-14 19:17:28 +00:00
parent 6bb600fe25
commit 1c2324f834
9 changed files with 258 additions and 99 deletions

View File

@ -43,6 +43,24 @@
case 'postMessage': case 'postMessage':
return this.previewer.send( 'setting', [ this.id, this() ] ); return this.previewer.send( 'setting', [ this.id, this() ] );
} }
},
/**
* Find controls associated with this setting.
*
* @since 4.6.0
* @returns {wp.customize.Control[]} Controls associated with setting.
*/
findControls: function() {
var setting = this, controls = [];
api.control.each( function( control ) {
_.each( control.settings, function( controlSetting ) {
if ( controlSetting.id === setting.id ) {
controls.push( control );
}
} );
} );
return controls;
} }
}); });
@ -1543,9 +1561,19 @@
control.setting = control.settings['default'] || null; control.setting = control.settings['default'] || null;
// Add setting notifications to the control notification.
_.each( control.settings, function( setting ) { _.each( control.settings, function( setting ) {
setting.notifications.bind( 'add', function( settingNotification ) { setting.notifications.bind( 'add', function( settingNotification ) {
var controlNotification = new api.Notification( setting.id + ':' + settingNotification.code, settingNotification ); var controlNotification, code, params;
code = setting.id + ':' + settingNotification.code;
params = _.extend(
{},
settingNotification,
{
setting: setting.id
}
);
controlNotification = new api.Notification( code, params );
control.notifications.add( controlNotification.code, controlNotification ); control.notifications.add( controlNotification.code, controlNotification );
} ); } );
setting.notifications.bind( 'remove', function( settingNotification ) { setting.notifications.bind( 'remove', function( settingNotification ) {
@ -2908,6 +2936,13 @@
} }
} ); } );
} ); } );
if ( data.settingValidities ) {
api._handleSettingValidities( {
settingValidities: data.settingValidities,
focusInvalidControl: false
} );
}
} ); } );
this.request = $.ajax( this.previewUrl(), { this.request = $.ajax( this.previewUrl(), {
@ -3430,68 +3465,14 @@
}; };
}, },
/**
* Handle invalid_settings in an error response for the customize-save request.
*
* Add notifications to the settings and focus on the first control that has an invalid setting.
*
* @since 4.6.0
* @private
*
* @param {object} response
* @param {object} response.invalid_settings
* @returns {void}
*/
_handleInvalidSettingsError: function( response ) {
var invalidControls = [], wasFocused = false;
if ( _.isEmpty( response.invalid_settings ) ) {
return;
}
// Find the controls that correspond to each invalid setting.
_.each( response.invalid_settings, function( notifications, settingId ) {
var setting = api( settingId );
if ( setting ) {
_.each( notifications, function( notificationParams, code ) {
var notification = new api.Notification( code, notificationParams );
setting.notifications.add( code, notification );
} );
}
api.control.each( function( control ) {
_.each( control.settings, function( controlSetting ) {
if ( controlSetting.id === settingId ) {
invalidControls.push( control );
}
} );
} );
} );
// Focus on the first control that is inside of an expanded section (one that is visible).
_( invalidControls ).find( function( control ) {
var isExpanded = control.section() && api.section.has( control.section() ) && api.section( control.section() ).expanded();
if ( isExpanded && control.expanded ) {
isExpanded = control.expanded();
}
if ( isExpanded ) {
control.focus();
wasFocused = true;
}
return wasFocused;
} );
// Focus on the first invalid control.
if ( ! wasFocused && invalidControls[0] ) {
invalidControls[0].focus();
}
},
save: function() { save: function() {
var self = this, var self = this,
processing = api.state( 'processing' ), processing = api.state( 'processing' ),
submitWhenDoneProcessing, submitWhenDoneProcessing,
submit, submit,
modifiedWhileSaving = {}; modifiedWhileSaving = {},
invalidSettings = [],
invalidControls;
body.addClass( 'saving' ); body.addClass( 'saving' );
@ -3502,6 +3483,27 @@
submit = function () { submit = function () {
var request, query; var request, query;
/*
* Block saving if there are any settings that are marked as
* invalid from the client (not from the server). Focus on
* the control.
*/
api.each( function( setting ) {
setting.notifications.each( function( notification ) {
if ( 'error' === notification.type && ( ! notification.data || ! notification.data.from_server ) ) {
invalidSettings.push( setting.id );
}
} );
} );
invalidControls = api.findControlsForSettings( invalidSettings );
if ( ! _.isEmpty( invalidControls ) ) {
_.values( invalidControls )[0][0].focus();
body.removeClass( 'saving' );
api.unbind( 'change', captureSettingModifiedDuringSave );
return;
}
query = $.extend( self.query(), { query = $.extend( self.query(), {
nonce: self.nonce.save nonce: self.nonce.save
} ); } );
@ -3512,18 +3514,6 @@
api.trigger( 'save', request ); api.trigger( 'save', request );
/*
* Remove all setting error notifications prior to save, allowing
* server to respond with fresh validation error notifications.
*/
api.each( function( setting ) {
setting.notifications.each( function( notification ) {
if ( 'error' === notification.type ) {
setting.notifications.remove( notification.code );
}
} );
} );
request.always( function () { request.always( function () {
body.removeClass( 'saving' ); body.removeClass( 'saving' );
saveBtn.prop( 'disabled', false ); saveBtn.prop( 'disabled', false );
@ -3548,7 +3538,12 @@
} ); } );
} }
self._handleInvalidSettingsError( response ); if ( response.setting_validities ) {
api._handleSettingValidities( {
settingValidities: response.setting_validities,
focusInvalidControl: true
} );
}
api.trigger( 'error', response ); api.trigger( 'error', response );
} ); } );
@ -3564,6 +3559,13 @@
api.previewer.send( 'saved', response ); api.previewer.send( 'saved', response );
if ( response.setting_validities ) {
api._handleSettingValidities( {
settingValidities: response.setting_validities,
focusInvalidControl: true
} );
}
api.trigger( 'saved', response ); api.trigger( 'saved', response );
// Restore the global dirty state if any settings were modified during save. // Restore the global dirty state if any settings were modified during save.
@ -3669,6 +3671,103 @@
}); });
}); });
/**
* Handle setting_validities in an error response for the customize-save request.
*
* Add notifications to the settings and focus on the first control that has an invalid setting.
*
* @since 4.6.0
* @private
*
* @param {object} args
* @param {object} args.settingValidities
* @param {boolean} [args.focusInvalidControl=false]
* @returns {void}
*/
api._handleSettingValidities = function handleSettingValidities( args ) {
var invalidSettingControls, invalidSettings = [], wasFocused = false;
// Find the controls that correspond to each invalid setting.
_.each( args.settingValidities, function( validity, settingId ) {
var setting = api( settingId );
if ( setting ) {
// Add notifications for invalidities.
if ( _.isObject( validity ) ) {
_.each( validity, function( params, code ) {
var notification = new api.Notification( code, params ), existingNotification, needsReplacement = false;
// Remove existing notification if already exists for code but differs in parameters.
existingNotification = setting.notifications( notification.code );
if ( existingNotification ) {
needsReplacement = ( notification.type !== existingNotification.type ) || ! _.isEqual( notification.data, existingNotification.data );
}
if ( needsReplacement ) {
setting.notifications.remove( code );
}
if ( ! setting.notifications.has( notification.code ) ) {
setting.notifications.add( code, notification );
}
invalidSettings.push( setting.id );
} );
}
// Remove notification errors that are no longer valid.
setting.notifications.each( function( notification ) {
if ( 'error' === notification.type && ( true === validity || ! validity[ notification.code ] ) ) {
setting.notifications.remove( notification.code );
}
} );
}
} );
if ( args.focusInvalidControl ) {
invalidSettingControls = api.findControlsForSettings( invalidSettings );
// Focus on the first control that is inside of an expanded section (one that is visible).
_( _.values( invalidSettingControls ) ).find( function( controls ) {
return _( controls ).find( function( control ) {
var isExpanded = control.section() && api.section.has( control.section() ) && api.section( control.section() ).expanded();
if ( isExpanded && control.expanded ) {
isExpanded = control.expanded();
}
if ( isExpanded ) {
control.focus();
wasFocused = true;
}
return wasFocused;
} );
} );
// Focus on the first invalid control.
if ( ! wasFocused && ! _.isEmpty( invalidSettingControls ) ) {
_.values( invalidSettingControls )[0][0].focus();
}
}
};
/**
* Find all controls associated with the given settings.
*
* @since 4.6.0
* @param {string[]} settingIds Setting IDs.
* @returns {object<string, wp.customize.Control>} Mapping setting ids to arrays of controls.
*/
api.findControlsForSettings = function findControlsForSettings( settingIds ) {
var controls = {}, settingControls;
_.each( _.unique( settingIds ), function( settingId ) {
var setting = api( settingId );
if ( setting ) {
settingControls = setting.findControls();
if ( settingControls && settingControls.length > 0 ) {
controls[ settingId ] = settingControls;
}
}
} );
return controls;
};
/** /**
* Sort panels, sections, controls by priorities. Hide empty sections and panels. * Sort panels, sections, controls by priorities. Hide empty sections and panels.
* *
@ -4040,6 +4139,14 @@
}); });
}); });
// Update the setting validities.
api.previewer.bind( 'selective-refresh-setting-validities', function handleSelectiveRefreshedSettingValidities( settingValidities ) {
api._handleSettingValidities( {
settingValidities: settingValidities,
focusInvalidControl: false
} );
} );
// Focus on the control that is associated with the given setting. // Focus on the control that is associated with the given setting.
api.previewer.bind( 'focus-control-for-setting', function( settingId ) { api.previewer.bind( 'focus-control-for-setting', function( settingId ) {
var matchedControl; var matchedControl;

File diff suppressed because one or more lines are too long

View File

@ -825,6 +825,9 @@ final class WP_Customize_Manager {
* @since 3.4.0 * @since 3.4.0
*/ */
public function customize_preview_settings() { public function customize_preview_settings() {
$setting_validities = $this->validate_setting_values( $this->unsanitized_post_values() );
$exported_setting_validities = array_map( array( $this, 'prepare_setting_validity_for_js' ), $setting_validities );
$settings = array( $settings = array(
'theme' => array( 'theme' => array(
'stylesheet' => $this->get_stylesheet(), 'stylesheet' => $this->get_stylesheet(),
@ -837,6 +840,7 @@ final class WP_Customize_Manager {
'activePanels' => array(), 'activePanels' => array(),
'activeSections' => array(), 'activeSections' => array(),
'activeControls' => array(), 'activeControls' => array(),
'settingValidities' => $exported_setting_validities,
'nonce' => $this->get_nonces(), 'nonce' => $this->get_nonces(),
'l10n' => array( 'l10n' => array(
'shiftClickToEdit' => __( 'Shift-click to edit this element.' ), 'shiftClickToEdit' => __( 'Shift-click to edit this element.' ),
@ -991,12 +995,13 @@ final class WP_Customize_Manager {
* @since 4.6.0 * @since 4.6.0
* @access public * @access public
* @see WP_REST_Request::has_valid_params() * @see WP_REST_Request::has_valid_params()
* @see WP_Customize_Setting::validate()
* *
* @param array $setting_values Mapping of setting IDs to values to sanitize and validate. * @param array $setting_values Mapping of setting IDs to values to sanitize and validate.
* @return array Empty array if all settings were valid. One or more instances of `WP_Error` if any were invalid. * @return array Mapping of setting IDs to return value of validate method calls, either `true` or `WP_Error`.
*/ */
public function validate_setting_values( $setting_values ) { public function validate_setting_values( $setting_values ) {
$validity_errors = array(); $validities = array();
foreach ( $setting_values as $setting_id => $unsanitized_value ) { foreach ( $setting_values as $setting_id => $unsanitized_value ) {
$setting = $this->get_setting( $setting_id ); $setting = $this->get_setting( $setting_id );
if ( ! $setting || is_null( $unsanitized_value ) ) { if ( ! $setting || is_null( $unsanitized_value ) ) {
@ -1006,11 +1011,46 @@ final class WP_Customize_Manager {
if ( false === $validity || null === $validity ) { if ( false === $validity || null === $validity ) {
$validity = new WP_Error( 'invalid_value', __( 'Invalid value.' ) ); $validity = new WP_Error( 'invalid_value', __( 'Invalid value.' ) );
} }
$validities[ $setting_id ] = $validity;
}
return $validities;
}
/**
* Prepare setting validity for exporting to the client (JS).
*
* Converts `WP_Error` instance into array suitable for passing into the
* `wp.customize.Notification` JS model.
*
* @since 4.6.0
* @access public
*
* @param true|WP_Error $validity Setting validity.
* @return true|array If `$validity` was `WP_Error` then array mapping the error
* codes to their respective `message` and `data` to pass
* into the `wp.customize.Notification` JS model.
*/
public function prepare_setting_validity_for_js( $validity ) {
if ( is_wp_error( $validity ) ) { if ( is_wp_error( $validity ) ) {
$validity_errors[ $setting_id ] = $validity; $notification = array();
foreach ( $validity->errors as $error_code => $error_messages ) {
$error_data = $validity->get_error_data( $error_code );
if ( is_null( $error_data ) ) {
$error_data = array();
} }
$error_data = array_merge(
$error_data,
array( 'from_server' => true )
);
$notification[ $error_code ] = array(
'message' => join( ' ', $error_messages ),
'data' => $error_data,
);
}
return $notification;
} else {
return true;
} }
return $validity_errors;
} }
/** /**
@ -1041,22 +1081,13 @@ final class WP_Customize_Manager {
do_action( 'customize_save_validation_before', $this ); do_action( 'customize_save_validation_before', $this );
// Validate settings. // Validate settings.
$validity_errors = $this->validate_setting_values( $this->unsanitized_post_values() ); $setting_validities = $this->validate_setting_values( $this->unsanitized_post_values() );
$invalid_count = count( $validity_errors ); $invalid_setting_count = count( array_filter( $setting_validities, 'is_wp_error' ) );
if ( $invalid_count > 0 ) { $exported_setting_validities = array_map( array( $this, 'prepare_setting_validity_for_js' ), $setting_validities );
$settings_errors = array(); if ( $invalid_setting_count > 0 ) {
foreach ( $validity_errors as $setting_id => $validity_error ) {
$settings_errors[ $setting_id ] = array();
foreach ( $validity_error->errors as $error_code => $error_messages ) {
$settings_errors[ $setting_id ][ $error_code ] = array(
'message' => join( ' ', $error_messages ),
'data' => $validity_error->get_error_data( $error_code ),
);
}
}
$response = array( $response = array(
'invalid_settings' => $settings_errors, 'setting_validities' => $exported_setting_validities,
'message' => sprintf( _n( 'There is %s invalid setting.', 'There are %s invalid settings.', $invalid_count ), number_format_i18n( $invalid_count ) ), 'message' => sprintf( _n( 'There is %s invalid setting.', 'There are %s invalid settings.', $invalid_setting_count ), number_format_i18n( $invalid_setting_count ) ),
); );
/** This filter is documented in wp-includes/class-wp-customize-manager.php */ /** This filter is documented in wp-includes/class-wp-customize-manager.php */
@ -1097,6 +1128,10 @@ final class WP_Customize_Manager {
*/ */
do_action( 'customize_save_after', $this ); do_action( 'customize_save_after', $this );
$data = array(
'setting_validities' => $exported_setting_validities,
);
/** /**
* Filters response data for a successful customize_save AJAX request. * Filters response data for a successful customize_save AJAX request.
* *
@ -1108,7 +1143,7 @@ final class WP_Customize_Manager {
* event on `wp.customize`. * event on `wp.customize`.
* @param WP_Customize_Manager $this WP_Customize_Manager instance. * @param WP_Customize_Manager $this WP_Customize_Manager instance.
*/ */
$response = apply_filters( 'customize_save_response', array(), $this ); $response = apply_filters( 'customize_save_response', $data, $this );
wp_send_json_success( $response ); wp_send_json_success( $response );
} }

View File

@ -402,6 +402,10 @@ final class WP_Customize_Selective_Refresh {
$response['errors'] = $this->triggered_errors; $response['errors'] = $this->triggered_errors;
} }
$setting_validities = $this->manager->validate_setting_values( $this->manager->unsanitized_post_values() );
$exported_setting_validities = array_map( array( $this->manager, 'prepare_setting_validity_for_js' ), $setting_validities );
$response['setting_validities'] = $exported_setting_validities;
/** /**
* Filters the response from rendering the partials. * Filters the response from rendering the partials.
* *

View File

@ -172,7 +172,8 @@
api.preview.send( 'ready', { api.preview.send( 'ready', {
activePanels: api.settings.activePanels, activePanels: api.settings.activePanels,
activeSections: api.settings.activeSections, activeSections: api.settings.activeSections,
activeControls: api.settings.activeControls activeControls: api.settings.activeControls,
settingValidities: api.settings.settingValidities
} ); } );
// Display a loading indicator when preview is reloading, and remove on failure. // Display a loading indicator when preview is reloading, and remove on failure.

View File

@ -1 +1 @@
!function(a,b){var c,d=wp.customize;c=function(a,b,c){var d;return function(){var e=arguments;c=c||this,clearTimeout(d),d=setTimeout(function(){d=null,a.apply(c,e)},b)}},d.Preview=d.Messenger.extend({initialize:function(a,e){var f=this;d.Messenger.prototype.initialize.call(this,a,e),this.body=b(document.body),this.body.on("click.preview","a",function(a){var c,d;c=b(this),d="#"===c.attr("href").substr(0,1),a.preventDefault(),d&&"#"!==c.attr("href")&&b(c.attr("href")).each(function(){this.scrollIntoView()}),a.shiftKey||d||(f.send("scroll",0),f.send("url",c.prop("href")))}),this.body.on("submit.preview","form",function(a){a.preventDefault()}),this.window=b(window),this.window.on("scroll.preview",c(function(){f.send("scroll",f.window.scrollTop())},200)),this.bind("scroll",function(a){f.window.scrollTop(a)})}}),b(function(){var a,c;d.settings=window._wpCustomizeSettings,d.settings&&(d.preview=new d.Preview({url:window.location.href,channel:d.settings.channel}),c=function(a,b,c){var e=d(a);e?e.set(b):(c=c||!1,e=d.create(a,b,{id:a}),c&&(e._dirty=!0))},d.preview.bind("settings",function(a){b.each(a,c)}),d.preview.trigger("settings",d.settings.values),b.each(d.settings._dirty,function(a,b){var c=d(b);c&&(c._dirty=!0)}),d.preview.bind("setting",function(a){var b=!0;c.apply(null,a.concat(b))}),d.preview.bind("sync",function(a){b.each(a,function(a,b){d.preview.trigger(a,b)}),d.preview.send("synced")}),d.preview.bind("active",function(){d.preview.send("nonce",d.settings.nonce),d.preview.send("documentTitle",document.title)}),d.preview.bind("saved",function(a){d.trigger("saved",a)}),d.bind("saved",function(){d.each(function(a){a._dirty=!1})}),d.preview.bind("nonce-refresh",function(a){b.extend(d.settings.nonce,a)}),d.preview.send("ready",{activePanels:d.settings.activePanels,activeSections:d.settings.activeSections,activeControls:d.settings.activeControls}),d.preview.bind("loading-initiated",function(){b("body").addClass("wp-customizer-unloading")}),d.preview.bind("loading-failed",function(){b("body").removeClass("wp-customizer-unloading")}),a=b.map(["color","image","position_x","repeat","attachment"],function(a){return"background_"+a}),d.when.apply(d,a).done(function(a,c,d,e,f){var g,h=b(document.body),i=b("head"),j=b("#custom-background-css");g=function(){var g="";h.toggleClass("custom-background",!(!a()&&!c())),a()&&(g+="background-color: "+a()+";"),c()&&(g+='background-image: url("'+c()+'");',g+="background-position: top "+d()+";",g+="background-repeat: "+e()+";",g+="background-attachment: "+f()+";"),j.remove(),j=b('<style type="text/css" id="custom-background-css">body.custom-background { '+g+" }</style>").appendTo(i)},b.each(arguments,function(){this.bind(g)})}),d("custom_logo",function(a){b("body").toggleClass("wp-custom-logo",!!a.get()),a.bind(function(a){b("body").toggleClass("wp-custom-logo",!!a)})}),d.trigger("preview-ready"))})}(wp,jQuery); !function(a,b){var c,d=wp.customize;c=function(a,b,c){var d;return function(){var e=arguments;c=c||this,clearTimeout(d),d=setTimeout(function(){d=null,a.apply(c,e)},b)}},d.Preview=d.Messenger.extend({initialize:function(a,e){var f=this;d.Messenger.prototype.initialize.call(this,a,e),this.body=b(document.body),this.body.on("click.preview","a",function(a){var c,d;c=b(this),d="#"===c.attr("href").substr(0,1),a.preventDefault(),d&&"#"!==c.attr("href")&&b(c.attr("href")).each(function(){this.scrollIntoView()}),a.shiftKey||d||(f.send("scroll",0),f.send("url",c.prop("href")))}),this.body.on("submit.preview","form",function(a){a.preventDefault()}),this.window=b(window),this.window.on("scroll.preview",c(function(){f.send("scroll",f.window.scrollTop())},200)),this.bind("scroll",function(a){f.window.scrollTop(a)})}}),b(function(){var a,c;d.settings=window._wpCustomizeSettings,d.settings&&(d.preview=new d.Preview({url:window.location.href,channel:d.settings.channel}),c=function(a,b,c){var e=d(a);e?e.set(b):(c=c||!1,e=d.create(a,b,{id:a}),c&&(e._dirty=!0))},d.preview.bind("settings",function(a){b.each(a,c)}),d.preview.trigger("settings",d.settings.values),b.each(d.settings._dirty,function(a,b){var c=d(b);c&&(c._dirty=!0)}),d.preview.bind("setting",function(a){var b=!0;c.apply(null,a.concat(b))}),d.preview.bind("sync",function(a){b.each(a,function(a,b){d.preview.trigger(a,b)}),d.preview.send("synced")}),d.preview.bind("active",function(){d.preview.send("nonce",d.settings.nonce),d.preview.send("documentTitle",document.title)}),d.preview.bind("saved",function(a){d.trigger("saved",a)}),d.bind("saved",function(){d.each(function(a){a._dirty=!1})}),d.preview.bind("nonce-refresh",function(a){b.extend(d.settings.nonce,a)}),d.preview.send("ready",{activePanels:d.settings.activePanels,activeSections:d.settings.activeSections,activeControls:d.settings.activeControls,settingValidities:d.settings.settingValidities}),d.preview.bind("loading-initiated",function(){b("body").addClass("wp-customizer-unloading")}),d.preview.bind("loading-failed",function(){b("body").removeClass("wp-customizer-unloading")}),a=b.map(["color","image","position_x","repeat","attachment"],function(a){return"background_"+a}),d.when.apply(d,a).done(function(a,c,d,e,f){var g,h=b(document.body),i=b("head"),j=b("#custom-background-css");g=function(){var g="";h.toggleClass("custom-background",!(!a()&&!c())),a()&&(g+="background-color: "+a()+";"),c()&&(g+='background-image: url("'+c()+'");',g+="background-position: top "+d()+";",g+="background-repeat: "+e()+";",g+="background-attachment: "+f()+";"),j.remove(),j=b('<style type="text/css" id="custom-background-css">body.custom-background { '+g+" }</style>").appendTo(i)},b.each(arguments,function(){this.bind(g)})}),d("custom_logo",function(a){b("body").toggleClass("wp-custom-logo",!!a.get()),a.bind(function(a){b("body").toggleClass("wp-custom-logo",!!a)})}),d.trigger("preview-ready"))})}(wp,jQuery);

View File

@ -847,6 +847,18 @@ wp.customize.selectiveRefresh = ( function( $, api ) {
} }
} ); } );
/**
* Handle setting validities in partial refresh response.
*
* @param {object} data Response data.
* @param {object} data.setting_validities Setting validities.
*/
api.selectiveRefresh.bind( 'render-partials-response', function handleSettingValiditiesResponse( data ) {
if ( data.setting_validities ) {
api.preview.send( 'selective-refresh-setting-validities', data.setting_validities );
}
} );
api.preview.bind( 'active', function() { api.preview.bind( 'active', function() {
// Make all partials ready. // Make all partials ready.

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.6-alpha-37699'; $wp_version = '4.6-alpha-37700';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.