in AKS-Demos/WordPress-Demo/Code/public/wp-admin/js/customize-controls.js [7476:7695]
submit = function () {
var request, query, settingInvalidities = {}, latestRevision = api._latestRevision, errorCode = 'client_side_error';
api.bind( 'change', captureSettingModifiedDuringSave );
api.notifications.remove( errorCode );
/*
* 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.fromServer ) {
invalidSettings.push( setting.id );
if ( ! settingInvalidities[ setting.id ] ) {
settingInvalidities[ setting.id ] = {};
}
settingInvalidities[ setting.id ][ notification.code ] = notification;
}
} );
} );
// Find all invalid setting less controls with notification type error.
api.control.each( function( control ) {
if ( ! control.setting || ! control.setting.id && control.active.get() ) {
control.notifications.each( function( notification ) {
if ( 'error' === notification.type ) {
invalidSettingLessControls.push( [ control ] );
}
} );
}
} );
invalidControls = _.union( invalidSettingLessControls, _.values( api.findControlsForSettings( invalidSettings ) ) );
if ( ! _.isEmpty( invalidControls ) ) {
invalidControls[0][0].focus();
api.unbind( 'change', captureSettingModifiedDuringSave );
if ( invalidSettings.length ) {
api.notifications.add( new api.Notification( errorCode, {
message: ( 1 === invalidSettings.length ? api.l10n.saveBlockedError.singular : api.l10n.saveBlockedError.plural ).replace( /%s/g, String( invalidSettings.length ) ),
type: 'error',
dismissible: true,
saveFailure: true
} ) );
}
deferred.rejectWith( previewer, [
{ setting_invalidities: settingInvalidities }
] );
api.state( 'saving' ).set( false );
return deferred.promise();
}
/*
* Note that excludeCustomizedSaved is intentionally false so that the entire
* set of customized data will be included if bypassed changeset update.
*/
query = $.extend( previewer.query( { excludeCustomizedSaved: false } ), {
nonce: previewer.nonce.save,
customize_changeset_status: changesetStatus
} );
if ( args && args.date ) {
query.customize_changeset_date = args.date;
} else if ( 'future' === changesetStatus && selectedChangesetDate ) {
query.customize_changeset_date = selectedChangesetDate;
}
if ( args && args.title ) {
query.customize_changeset_title = args.title;
}
// Allow plugins to modify the params included with the save request.
api.trigger( 'save-request-params', query );
/*
* Note that the dirty customized values will have already been set in the
* changeset and so technically query.customized could be deleted. However,
* it is remaining here to make sure that any settings that got updated
* quietly which may have not triggered an update request will also get
* included in the values that get saved to the changeset. This will ensure
* that values that get injected via the saved event will be included in
* the changeset. This also ensures that setting values that were invalid
* will get re-validated, perhaps in the case of settings that are invalid
* due to dependencies on other settings.
*/
request = wp.ajax.post( 'customize_save', query );
api.state( 'processing' ).set( api.state( 'processing' ).get() + 1 );
api.trigger( 'save', request );
request.always( function () {
api.state( 'processing' ).set( api.state( 'processing' ).get() - 1 );
api.state( 'saving' ).set( false );
api.unbind( 'change', captureSettingModifiedDuringSave );
} );
// Remove notifications that were added due to save failures.
api.notifications.each( function( notification ) {
if ( notification.saveFailure ) {
api.notifications.remove( notification.code );
}
});
request.fail( function ( response ) {
var notification, notificationArgs;
notificationArgs = {
type: 'error',
dismissible: true,
fromServer: true,
saveFailure: true
};
if ( '0' === response ) {
response = 'not_logged_in';
} else if ( '-1' === response ) {
// Back-compat in case any other check_ajax_referer() call is dying.
response = 'invalid_nonce';
}
if ( 'invalid_nonce' === response ) {
previewer.cheatin();
} else if ( 'not_logged_in' === response ) {
previewer.preview.iframe.hide();
previewer.login().done( function() {
previewer.save();
previewer.preview.iframe.show();
} );
} else if ( response.code ) {
if ( 'not_future_date' === response.code && api.section.has( 'publish_settings' ) && api.section( 'publish_settings' ).active.get() && api.control.has( 'changeset_scheduled_date' ) ) {
api.control( 'changeset_scheduled_date' ).toggleFutureDateNotification( true ).focus();
} else if ( 'changeset_locked' !== response.code ) {
notification = new api.Notification( response.code, _.extend( notificationArgs, {
message: response.message
} ) );
}
} else {
notification = new api.Notification( 'unknown_error', _.extend( notificationArgs, {
message: api.l10n.unknownRequestFail
} ) );
}
if ( notification ) {
api.notifications.add( notification );
}
if ( response.setting_validities ) {
api._handleSettingValidities( {
settingValidities: response.setting_validities,
focusInvalidControl: true
} );
}
deferred.rejectWith( previewer, [ response ] );
api.trigger( 'error', response );
// Start a new changeset if the underlying changeset was published.
if ( 'changeset_already_published' === response.code && response.next_changeset_uuid ) {
api.settings.changeset.uuid = response.next_changeset_uuid;
api.state( 'changesetStatus' ).set( '' );
if ( api.settings.changeset.branching ) {
parent.send( 'changeset-uuid', api.settings.changeset.uuid );
}
api.previewer.send( 'changeset-uuid', api.settings.changeset.uuid );
}
} );
request.done( function( response ) {
previewer.send( 'saved', response );
api.state( 'changesetStatus' ).set( response.changeset_status );
if ( response.changeset_date ) {
api.state( 'changesetDate' ).set( response.changeset_date );
}
if ( 'publish' === response.changeset_status ) {
// Mark all published as clean if they haven't been modified during the request.
api.each( function( setting ) {
/*
* Note that the setting revision will be undefined in the case of setting
* values that are marked as dirty when the customizer is loaded, such as
* when applying starter content. All other dirty settings will have an
* associated revision due to their modification triggering a change event.
*/
if ( setting._dirty && ( _.isUndefined( api._latestSettingRevisions[ setting.id ] ) || api._latestSettingRevisions[ setting.id ] <= latestRevision ) ) {
setting._dirty = false;
}
} );
api.state( 'changesetStatus' ).set( '' );
api.settings.changeset.uuid = response.next_changeset_uuid;
if ( api.settings.changeset.branching ) {
parent.send( 'changeset-uuid', api.settings.changeset.uuid );
}
}
// Prevent subsequent requestChangesetUpdate() calls from including the settings that have been saved.
api._lastSavedRevision = Math.max( latestRevision, api._lastSavedRevision );
if ( response.setting_validities ) {
api._handleSettingValidities( {
settingValidities: response.setting_validities,
focusInvalidControl: true
} );
}
deferred.resolveWith( previewer, [ response ] );
api.trigger( 'saved', response );
// Restore the global dirty state if any settings were modified during save.
if ( ! _.isEmpty( modifiedWhileSaving ) ) {
api.state( 'saved' ).set( false );
}
} );
};