Changeset 27909
- Timestamp:
- 04/02/2014 06:20:00 PM (11 years ago)
- Location:
- trunk/src/wp-admin
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/css/customize-widgets.css
r27824 r27909 37 37 .customize-control-widget_form.previewer-loading .spinner { 38 38 opacity: 1.0; 39 } 40 .customize-control-widget_form.widget-form-disabled .widget-content { 41 opacity: 0.7; 42 pointer-events: none; 43 -moz-user-select: none; 44 -webkit-user-select: none; 45 -ms-user-select: none; 46 user-select: none; 39 47 } 40 48 -
trunk/src/wp-admin/js/customize-widgets.js
r27907 r27909 9 9 SidebarCollection, 10 10 OldPreviewer, 11 builtin_form_sync_handlers, 11 12 customize = wp.customize, self = { 12 13 nonce: null, … … 132 133 133 134 /** 135 * Handlers for the widget-synced event, organized by widget ID base. 136 * Other widgets may provide their own update handlers by adding 137 * listeners for the widget-synced event. 138 */ 139 builtin_form_sync_handlers = { 140 141 /** 142 * @param {jQuery.Event} e 143 * @param {jQuery} widget_el 144 * @param {String} new_form 145 */ 146 rss: function ( e, widget_el, new_form ) { 147 var old_widget_error = widget_el.find( '.widget-error:first' ), 148 new_widget_error = $( '<div>' + new_form + '</div>' ).find( '.widget-error:first' ); 149 150 if ( old_widget_error.length && new_widget_error.length ) { 151 old_widget_error.replaceWith( new_widget_error ); 152 } else if ( old_widget_error.length ) { 153 old_widget_error.remove(); 154 } else if ( new_widget_error.length ) { 155 widget_el.find( '.widget-content:first' ).prepend( new_widget_error ); 156 } 157 } 158 }; 159 160 /** 134 161 * On DOM ready, initialize some meta functionality independent of specific 135 162 * customizer controls. … … 455 482 var control = this, 456 483 control_html, 484 widget_el, 457 485 customize_control_type = 'widget_form', 458 486 customize_control, … … 489 517 widget.set( 'is_disabled', true ); // Prevent single widget from being added again now 490 518 } 519 widget_el = $( control_html ); 491 520 492 521 customize_control = $( '<li></li>' ); 493 522 customize_control.addClass( 'customize-control' ); 494 523 customize_control.addClass( 'customize-control-' + customize_control_type ); 495 customize_control.append( $( control_html ));524 customize_control.append( widget_el ); 496 525 customize_control.find( '> .widget-icon' ).remove(); 497 526 if ( widget.get( 'is_multi' ) ) { … … 579 608 } ); 580 609 610 $( document ).trigger( 'widget-added', [ widget_el ] ); 611 581 612 return widget_form_control; 582 613 } … … 603 634 control._setupUpdateUI(); 604 635 control._setupRemoveUI(); 605 control.hook( 'init' );606 },607 608 /**609 * Hooks for widgets to support living in the customizer control610 */611 hooks: {612 _default: {},613 rss: {614 formUpdated: function ( serialized_form ) {615 var control = this,616 old_widget_error = control.container.find( '.widget-error:first' ),617 new_widget_error = serialized_form.find( '.widget-error:first' );618 619 if ( old_widget_error.length && new_widget_error.length ) {620 old_widget_error.replaceWith( new_widget_error );621 } else if ( old_widget_error.length ) {622 old_widget_error.remove();623 } else if ( new_widget_error.length ) {624 control.container.find( '.widget-content' ).prepend( new_widget_error );625 }626 }627 }628 },629 630 /**631 * Trigger an 'action' which a specific widget type can handle632 *633 * @param name634 */635 hook: function ( name ) {636 var args = Array.prototype.slice.call( arguments, 1 ), handler;637 638 if ( this.hooks[this.params.widget_id_base] && this.hooks[this.params.widget_id_base][name] ) {639 handler = this.hooks[this.params.widget_id_base][name];640 } else if ( this.hooks._default[name] ) {641 handler = this.hooks._default[name];642 }643 if ( handler ) {644 handler.apply( this, args );645 }646 636 }, 647 637 … … 661 651 control._update_count = 0; 662 652 control.is_widget_updating = false; 653 control.live_update_mode = true; 663 654 664 655 // Update widget whenever model changes … … 946 937 _setupUpdateUI: function () { 947 938 var control = this, 939 widget_root, 948 940 widget_content, 949 941 save_btn, 950 update_widget_debounced; 951 952 widget_content = control.container.find( '.widget-content' ); 942 update_widget_debounced, 943 form_update_event_handler; 944 945 widget_root = control.container.find( '.widget:first' ); 946 widget_content = widget_root.find( '.widget-content:first' ); 953 947 954 948 // Configure update button … … 959 953 save_btn.on( 'click', function ( e ) { 960 954 e.preventDefault(); 961 control.updateWidget( );955 control.updateWidget( { disable_form: true } ); 962 956 } ); 963 957 … … 977 971 // Handle widgets that support live previews 978 972 widget_content.on( 'change input propertychange', ':input', function ( e ) { 979 if ( e.type === 'change' ) { 980 control.updateWidget(); 981 } else if ( this.checkValidity && this.checkValidity() ) { 982 update_widget_debounced(); 973 if ( control.live_update_mode ) { 974 if ( e.type === 'change' ) { 975 control.updateWidget(); 976 } else if ( this.checkValidity && this.checkValidity() ) { 977 update_widget_debounced(); 978 } 983 979 } 984 980 } ); … … 999 995 control.container.toggleClass( 'widget-rendered', is_rendered ); 1000 996 } ); 997 998 form_update_event_handler = builtin_form_sync_handlers[ control.params.widget_id_base ]; 999 if ( form_update_event_handler ) { 1000 $( document ).on( 'widget-synced', function ( e, widget_el ) { 1001 if ( widget_root.is( widget_el ) ) { 1002 form_update_event_handler.apply( document, arguments ); 1003 } 1004 } ); 1005 } 1001 1006 }, 1002 1007 … … 1056 1061 1057 1062 /** 1063 * Find all inputs in a widget container that should be considered when 1064 * comparing the loaded form with the sanitized form, whose fields will 1065 * be aligned to copy the sanitized over. The elements returned by this 1066 * are passed into this._getInputsSignature(), and they are iterated 1067 * over when copying sanitized values over to the the form loaded. 1068 * 1069 * @param {jQuery} container element in which to look for inputs 1070 * @returns {jQuery} inputs 1071 * @private 1072 */ 1073 _getInputs: function ( container ) { 1074 return $( container ).find( ':input[name]' ); 1075 }, 1076 1077 /** 1058 1078 * Iterate over supplied inputs and create a signature string for all of them together. 1059 1079 * This string can be used to compare whether or not the form has all of the same fields. … … 1067 1087 input = $( input ); 1068 1088 var signature_parts; 1069 if ( input.is( 'option' ) ) { 1070 signature_parts = [ input.prop( 'nodeName' ), input.prop( 'value' ) ]; 1071 } else if ( input.is( ':checkbox, :radio' ) ) { 1072 signature_parts = [ input.prop( 'type' ), input.attr( 'id' ), input.attr( 'name' ), input.prop( 'value' ) ]; 1089 if ( input.is( ':checkbox, :radio' ) ) { 1090 signature_parts = [ input.attr( 'id' ), input.attr( 'name' ), input.prop( 'value' ) ]; 1073 1091 } else { 1074 signature_parts = [ input. prop( 'nodeName' ), input.attr( 'id' ), input.attr( 'name' ), input.attr( 'type' ) ];1092 signature_parts = [ input.attr( 'id' ), input.attr( 'name' ) ]; 1075 1093 } 1076 1094 return signature_parts.join( ',' ); … … 1090 1108 if ( input.is( ':radio, :checkbox' ) ) { 1091 1109 return 'checked'; 1092 } else if ( input.is( 'option' ) ) {1093 return 'selected';1094 1110 } else { 1095 1111 return 'value'; … … 1128 1144 instance_override, 1129 1145 complete_callback, 1146 widget_root, 1130 1147 update_number, 1131 1148 widget_content, 1132 element_id_to_refocus = null,1133 active_input_selection_start = null,1134 active_input_selection_end = null,1135 1149 params, 1136 1150 data, 1137 1151 inputs, 1138 1152 processing, 1139 jqxhr; 1153 jqxhr, 1154 is_changed; 1140 1155 1141 1156 args = $.extend( { … … 1151 1166 update_number = control._update_count; 1152 1167 1153 widget_content = control.container.find( '.widget-content' ); 1168 widget_root = control.container.find( '.widget:first' ); 1169 widget_content = widget_root.find( '.widget-content:first' ); 1154 1170 1155 1171 // Remove a previous error message 1156 1172 widget_content.find( '.widget-error' ).remove(); 1157 1158 // @todo Support more selectors than IDs?1159 if ( $.contains( control.container[0], document.activeElement ) && $( document.activeElement ).is( '[id]' ) ) {1160 element_id_to_refocus = $( document.activeElement ).prop( 'id' );1161 // @todo IE8 support: http://stackoverflow.com/a/4207763/935791162 try {1163 active_input_selection_start = document.activeElement.selectionStart;1164 active_input_selection_end = document.activeElement.selectionEnd;1165 }1166 catch( e ) {} // catch InvalidStateError in case of checkboxes1167 }1168 1173 1169 1174 control.container.addClass( 'widget-form-loading' ); … … 1172 1177 processing( processing() + 1 ); 1173 1178 1179 if ( ! control.live_update_mode ) { 1180 control.container.addClass( 'widget-form-disabled' ); 1181 } 1182 1174 1183 params = {}; 1175 1184 params.action = 'update-widget'; … … 1178 1187 1179 1188 data = $.param( params ); 1180 inputs = widget_content.find( ':input, option');1189 inputs = control._getInputs( widget_content ); 1181 1190 1182 1191 // Store the value we're submitting in data so that when the response comes back, … … 1201 1210 sanitized_inputs, 1202 1211 has_same_inputs_in_response, 1203 is_ instance_identical;1212 is_live_update_aborted = false; 1204 1213 1205 1214 // Check if the user is logged out. … … 1221 1230 if ( r.success ) { 1222 1231 sanitized_form = $( '<div>' + r.data.form + '</div>' ); 1223 1224 control.hook( 'formUpdate', sanitized_form ); 1225 1226 sanitized_inputs = sanitized_form.find( ':input, option' ); 1232 sanitized_inputs = control._getInputs( sanitized_form ); 1227 1233 has_same_inputs_in_response = control._getInputsSignature( inputs ) === control._getInputsSignature( sanitized_inputs ); 1228 1234 1229 if ( has_same_inputs_in_response ) { 1235 // Restore live update mode if sanitized fields are now aligned with the existing fields 1236 if ( has_same_inputs_in_response && ! control.live_update_mode ) { 1237 control.live_update_mode = true; 1238 control.container.removeClass( 'widget-form-disabled' ); 1239 control.container.find( 'input[name="savewidget"]' ).hide(); 1240 } 1241 1242 // Sync sanitized field states to existing fields if they are aligned 1243 if ( has_same_inputs_in_response && control.live_update_mode ) { 1230 1244 inputs.each( function ( i ) { 1231 1245 var input = $( this ), 1232 1246 sanitized_input = $( sanitized_inputs[i] ), 1233 1247 property = control._getInputStatePropertyName( this ), 1234 state, 1235 sanitized_state; 1236 1237 state = input.data( 'state' + update_number ); 1248 submitted_state, 1249 sanitized_state, 1250 can_update_state; 1251 1252 submitted_state = input.data( 'state' + update_number ); 1238 1253 sanitized_state = sanitized_input.prop( property ); 1239 1254 input.data( 'sanitized', sanitized_state ); 1240 1255 1241 if ( state !== sanitized_state ) { 1242 1243 // Only update now if not currently focused on it, 1244 // so that we don't cause the cursor 1245 // it will be updated upon the change event 1246 if ( args.ignore_active_element || ! input.is( document.activeElement ) ) { 1247 input.prop( property, sanitized_state ); 1248 } 1249 control.hook( 'unsanitaryField', input, sanitized_state, state ); 1250 1251 } else { 1252 control.hook( 'sanitaryField', input, state ); 1256 can_update_state = ( 1257 submitted_state !== sanitized_state && 1258 ( args.ignore_active_element || ! input.is( document.activeElement ) ) 1259 ); 1260 if ( can_update_state ) { 1261 input.prop( property, sanitized_state ); 1253 1262 } 1254 1263 } ); 1255 control.hook( 'formUpdated', sanitized_form ); 1264 $( document ).trigger( 'widget-synced', [ widget_root, r.data.form ] ); 1265 1266 // Otherwise, if sanitized fields are not aligned with existing fields, disable live update mode if enabled 1267 } else if ( control.live_update_mode ) { 1268 control.live_update_mode = false; 1269 control.container.find( 'input[name="savewidget"]' ).show(); 1270 is_live_update_aborted = true; 1271 // Otherwise, replace existing form with the sanitized form 1256 1272 } else { 1257 widget_content.html( sanitized_form.html() ); 1258 if ( element_id_to_refocus ) { 1259 // not using jQuery selector so we don't have to worry about escaping IDs with brackets and other characters 1260 $( document.getElementById( element_id_to_refocus ) ) 1261 .prop( { 1262 selectionStart: active_input_selection_start, 1263 selectionEnd: active_input_selection_end 1264 } ) 1265 .focus(); 1266 } 1267 control.hook( 'formRefreshed' ); 1273 widget_content.html( r.data.form ); 1274 control.container.removeClass( 'widget-form-disabled' ); 1275 $( document ).trigger( 'widget-updated', [ widget_root ] ); 1268 1276 } 1269 1277 … … 1273 1281 * preview finishing loading. 1274 1282 */ 1275 is_ instance_identical =_( control.setting() ).isEqual( r.data.instance );1276 if ( ! is_instance_identical) {1283 is_changed = ! is_live_update_aborted && ! _( control.setting() ).isEqual( r.data.instance ); 1284 if ( is_changed ) { 1277 1285 control.is_widget_updating = true; // suppress triggering another updateWidget 1278 1286 control.setting( r.data.instance ); … … 1281 1289 1282 1290 if ( complete_callback ) { 1283 complete_callback.call( control, null, { no_change: is_instance_identical, ajax_finished: true } );1291 complete_callback.call( control, null, { no_change: ! is_changed, ajax_finished: true } ); 1284 1292 } 1285 1293 } else {
Note: See TracChangeset
for help on using the changeset viewer.