Changeset 40941
- Timestamp:
- 06/25/2017 06:47:13 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/widgets/media-widgets.js
r40939 r40941 436 436 * @param {Object} options - Options. 437 437 * @param {Backbone.Model} options.model - Model. 438 * @param {jQuery} options.el - Control container element. 438 * @param {jQuery} options.el - Control field container element. 439 * @param {jQuery} options.syncContainer - Container element where fields are synced for the server. 439 440 * @returns {void} 440 441 */ … … 444 445 Backbone.View.prototype.initialize.call( control, options ); 445 446 446 if ( ! control.el ) {447 throw new Error( 'Missing options.el' );448 }449 447 if ( ! ( control.model instanceof component.MediaWidgetModel ) ) { 450 448 throw new Error( 'Missing options.model' ); 451 449 } 450 if ( ! options.el ) { 451 throw new Error( 'Missing options.el' ); 452 } 453 if ( ! options.syncContainer ) { 454 throw new Error( 'Missing options.syncContainer' ); 455 } 456 457 control.syncContainer = options.syncContainer; 458 459 control.$el.addClass( 'media-widget-control' ); 452 460 453 461 // Allow methods to be passed in with control context preserved. … … 554 562 syncModelToInputs: function syncModelToInputs() { 555 563 var control = this; 556 control. $el.next( '.widget-content' ).find( '.media-widget-instance-property' ).each( function() {564 control.syncContainer.find( '.media-widget-instance-property' ).each( function() { 557 565 var input = $( this ), value; 558 566 value = control.model.get( input.data( 'property' ) ); … … 1010 1018 */ 1011 1019 component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) { 1012 var widgetContent, controlContainer, widgetForm, idBase, ControlConstructor, ModelConstructor, modelAttributes, widgetControl, widgetModel, widgetId, widgetInside, animatedCheckDelay = 50, renderWhenAnimationDone;1020 var fieldContainer, syncContainer, widgetForm, idBase, ControlConstructor, ModelConstructor, modelAttributes, widgetControl, widgetModel, widgetId, widgetInside, animatedCheckDelay = 50, renderWhenAnimationDone; 1013 1021 widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen. 1014 widgetContent = widgetForm.find( '> .widget-content' );1015 1022 idBase = widgetForm.find( '> .id_base' ).val(); 1016 1023 widgetId = widgetForm.find( '> .widget-id' ).val(); … … 1039 1046 * container. 1040 1047 */ 1041 controlContainer = $( '<div class="media-widget-control"></div>' ); 1042 widgetContent.before( controlContainer ); 1048 fieldContainer = $( '<div></div>' ); 1049 syncContainer = widgetContainer.find( '.widget-content:first' ); 1050 syncContainer.before( fieldContainer ); 1043 1051 1044 1052 /* … … 1048 1056 */ 1049 1057 modelAttributes = {}; 1050 widgetContent.find( '.media-widget-instance-property' ).each( function() {1058 syncContainer.find( '.media-widget-instance-property' ).each( function() { 1051 1059 var input = $( this ); 1052 1060 modelAttributes[ input.data( 'property' ) ] = input.val(); … … 1057 1065 1058 1066 widgetControl = new ControlConstructor({ 1059 el: controlContainer, 1067 el: fieldContainer, 1068 syncContainer: syncContainer, 1060 1069 model: widgetModel 1061 1070 }); … … 1083 1092 component.modelCollection.add( [ widgetModel ] ); 1084 1093 component.widgetControls[ widgetModel.get( 'widget_id' ) ] = widgetControl; 1094 }; 1095 1096 /** 1097 * Setup widget in accessibility mode. 1098 * 1099 * @returns {void} 1100 */ 1101 component.setupAccessibleMode = function setupAccessibleMode() { 1102 var widgetForm, widgetId, idBase, widgetControl, ControlConstructor, ModelConstructor, modelAttributes, fieldContainer, syncContainer; 1103 widgetForm = $( '.editwidget > form' ); 1104 if ( 0 === widgetForm.length ) { 1105 return; 1106 } 1107 1108 idBase = widgetForm.find( '> .widget-control-actions > .id_base' ).val(); 1109 1110 ControlConstructor = component.controlConstructors[ idBase ]; 1111 if ( ! ControlConstructor ) { 1112 return; 1113 } 1114 1115 widgetId = widgetForm.find( '> .widget-control-actions > .widget-id' ).val(); 1116 1117 ModelConstructor = component.modelConstructors[ idBase ] || component.MediaWidgetModel; 1118 fieldContainer = $( '<div></div>' ); 1119 syncContainer = widgetForm.find( '> .widget-inside' ); 1120 syncContainer.before( fieldContainer ); 1121 1122 modelAttributes = {}; 1123 syncContainer.find( '.media-widget-instance-property' ).each( function() { 1124 var input = $( this ); 1125 modelAttributes[ input.data( 'property' ) ] = input.val(); 1126 }); 1127 modelAttributes.widget_id = widgetId; 1128 1129 widgetControl = new ControlConstructor({ 1130 el: fieldContainer, 1131 syncContainer: syncContainer, 1132 model: new ModelConstructor( modelAttributes ) 1133 }); 1134 1135 component.modelCollection.add( [ widgetControl.model ] ); 1136 component.widgetControls[ widgetControl.model.get( 'widget_id' ) ] = widgetControl; 1137 1138 widgetControl.render(); 1085 1139 }; 1086 1140 … … 1153 1207 component.handleWidgetAdded( new jQuery.Event( 'widget-added' ), widgetContainer ); 1154 1208 }); 1209 1210 // Accessibility mode. 1211 $( window ).on( 'load', function() { 1212 component.setupAccessibleMode(); 1213 }); 1155 1214 }); 1156 1215 }; -
trunk/src/wp-admin/js/widgets/text-widgets.js
r40821 r40941 25 25 * Initialize. 26 26 * 27 * @param {Object} 28 * @param { Backbone.Model} options.model - Model.29 * @param {jQuery} options.el - Control container element.27 * @param {Object} options - Options. 28 * @param {jQuery} options.el - Control field container element. 29 * @param {jQuery} options.syncContainer - Container element where fields are synced for the server. 30 30 * @returns {void} 31 31 */ … … 36 36 throw new Error( 'Missing options.el' ); 37 37 } 38 if ( ! options.syncContainer ) { 39 throw new Error( 'Missing options.syncContainer' ); 40 } 38 41 39 42 Backbone.View.prototype.initialize.call( control, options ); 40 41 /* 42 * Create a container element for the widget control fields. 43 * This is inserted into the DOM immediately before the the .widget-content 44 * element because the contents of this element are essentially "managed" 45 * by PHP, where each widget update cause the entire element to be emptied 46 * and replaced with the rendered output of WP_Widget::form() which is 47 * sent back in Ajax request made to save/update the widget instance. 48 * To prevent a "flash of replaced DOM elements and re-initialized JS 49 * components", the JS template is rendered outside of the normal form 50 * container. 51 */ 52 control.fieldContainer = $( '<div class="text-widget-fields"></div>' ); 53 control.fieldContainer.html( wp.template( 'widget-text-control-fields' ) ); 54 control.widgetContentContainer = control.$el.find( '.widget-content:first' ); 55 control.widgetContentContainer.before( control.fieldContainer ); 43 control.syncContainer = options.syncContainer; 44 45 control.$el.addClass( 'text-widget-fields' ); 46 control.$el.html( wp.template( 'widget-text-control-fields' ) ); 56 47 57 48 control.fields = { 58 title: control. fieldContainer.find( '.title' ),59 text: control. fieldContainer.find( '.text' )49 title: control.$el.find( '.title' ), 50 text: control.$el.find( '.text' ) 60 51 }; 61 52 … … 63 54 _.each( control.fields, function( fieldInput, fieldName ) { 64 55 fieldInput.on( 'input change', function updateSyncField() { 65 var syncInput = control. widgetContentContainer.find( 'input[type=hidden].' + fieldName );56 var syncInput = control.syncContainer.find( 'input[type=hidden].' + fieldName ); 66 57 if ( syncInput.val() !== $( this ).val() ) { 67 58 syncInput.val( $( this ).val() ); … … 71 62 72 63 // Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event. 73 fieldInput.val( control. widgetContentContainer.find( 'input[type=hidden].' + fieldName ).val() );64 fieldInput.val( control.syncContainer.find( 'input[type=hidden].' + fieldName ).val() ); 74 65 }); 75 66 }, … … 88 79 89 80 if ( ! control.fields.title.is( document.activeElement ) ) { 90 syncInput = control. widgetContentContainer.find( 'input[type=hidden].title' );81 syncInput = control.syncContainer.find( 'input[type=hidden].title' ); 91 82 control.fields.title.val( syncInput.val() ); 92 83 } 93 84 94 syncInput = control. widgetContentContainer.find( 'input[type=hidden].text' );85 syncInput = control.syncContainer.find( 'input[type=hidden].text' ); 95 86 if ( control.fields.text.is( ':visible' ) ) { 96 87 if ( ! control.fields.text.is( document.activeElement ) ) { … … 220 211 */ 221 212 component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) { 222 var widgetForm, idBase, widgetControl, widgetId, animatedCheckDelay = 50, widgetInside, renderWhenAnimationDone ;213 var widgetForm, idBase, widgetControl, widgetId, animatedCheckDelay = 50, widgetInside, renderWhenAnimationDone, fieldContainer, syncContainer; 223 214 widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen. 224 215 … … 229 220 230 221 // Prevent initializing already-added widgets. 231 widgetId = widgetForm.find( ' >.widget-id' ).val();222 widgetId = widgetForm.find( '.widget-id' ).val(); 232 223 if ( component.widgetControls[ widgetId ] ) { 233 224 return; 234 225 } 235 226 227 /* 228 * Create a container element for the widget control fields. 229 * This is inserted into the DOM immediately before the the .widget-content 230 * element because the contents of this element are essentially "managed" 231 * by PHP, where each widget update cause the entire element to be emptied 232 * and replaced with the rendered output of WP_Widget::form() which is 233 * sent back in Ajax request made to save/update the widget instance. 234 * To prevent a "flash of replaced DOM elements and re-initialized JS 235 * components", the JS template is rendered outside of the normal form 236 * container. 237 */ 238 fieldContainer = $( '<div></div>' ); 239 syncContainer = widgetContainer.find( '.widget-content:first' ); 240 syncContainer.before( fieldContainer ); 241 236 242 widgetControl = new component.TextWidgetControl({ 237 el: widgetContainer 243 el: fieldContainer, 244 syncContainer: syncContainer 238 245 }); 239 246 … … 255 262 }; 256 263 renderWhenAnimationDone(); 264 }; 265 266 /** 267 * Setup widget in accessibility mode. 268 * 269 * @returns {void} 270 */ 271 component.setupAccessibleMode = function setupAccessibleMode() { 272 var widgetForm, idBase, widgetControl, fieldContainer, syncContainer; 273 widgetForm = $( '.editwidget > form' ); 274 if ( 0 === widgetForm.length ) { 275 return; 276 } 277 278 idBase = widgetForm.find( '> .widget-control-actions > .id_base' ).val(); 279 if ( 'text' !== idBase ) { 280 return; 281 } 282 283 fieldContainer = $( '<div></div>' ); 284 syncContainer = widgetForm.find( '> .widget-inside' ); 285 syncContainer.before( fieldContainer ); 286 287 widgetControl = new component.TextWidgetControl({ 288 el: fieldContainer, 289 syncContainer: syncContainer 290 }); 291 292 widgetControl.initializeEditor(); 257 293 }; 258 294 … … 320 356 component.handleWidgetAdded( new jQuery.Event( 'widget-added' ), widgetContainer ); 321 357 }); 358 359 // Accessibility mode. 360 $( window ).on( 'load', function() { 361 component.setupAccessibleMode(); 362 }); 322 363 }); 323 364 }; -
trunk/tests/qunit/wp-admin/js/widgets/test-media-image-widget.js
r40640 r40941 18 18 imageWidgetModelInstance = new wp.mediaWidgets.modelConstructors.media_image(); 19 19 imageWidgetControlInstance = new ImageWidgetControl({ 20 el: jQuery( '<div></div>' ), 21 syncContainer: jQuery( '<div></div>' ), 20 22 model: imageWidgetModelInstance 21 23 }); … … 85 87 imageWidgetModelInstance = new wp.mediaWidgets.modelConstructors.media_image(); 86 88 imageWidgetControlInstance = new wp.mediaWidgets.controlConstructors.media_image({ 89 el: jQuery( '<div></div>' ), 90 syncContainer: jQuery( '<div></div>' ), 87 91 model: imageWidgetModelInstance 88 92 }); -
trunk/tests/qunit/wp-admin/js/widgets/test-media-video-widget.js
r40810 r40941 18 18 videoWidgetModelInstance = new wp.mediaWidgets.modelConstructors.media_video(); 19 19 videoWidgetControlInstance = new VideoWidgetControl({ 20 el: jQuery( '<div></div>' ), 21 syncContainer: jQuery( '<div></div>' ), 20 22 model: videoWidgetModelInstance 21 23 }); … … 47 49 videoWidgetModelInstance = new wp.mediaWidgets.modelConstructors.media_video(); 48 50 videoWidgetControlInstance = new wp.mediaWidgets.controlConstructors.media_video({ 51 el: jQuery( '<div></div>' ), 52 syncContainer: jQuery( '<div></div>' ), 49 53 model: videoWidgetModelInstance 50 54 });
Note: See TracChangeset
for help on using the changeset viewer.