Ticket #42083: 30741.0.diff
File 30741.0.diff, 42.9 KB (added by , 7 years ago) |
---|
-
src/wp-admin/js/customize-controls.js
diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js index f2f6196281..bcfe9a8278 100644
30 30 initialize: function( code, params ) { 31 31 var notification = this; 32 32 api.Notification.prototype.initialize.call( notification, code, params ); 33 notification.c lasses += ' notification-overlay';33 notification.containerClasses += ' notification-overlay'; 34 34 if ( notification.loading ) { 35 notification.c lasses += ' notification-loading';35 notification.containerClasses += ' notification-loading'; 36 36 } 37 37 } 38 38 }); … … 105 105 * Add notification to the collection. 106 106 * 107 107 * @since 4.9.0 108 * @param {string} code - Notification code. 109 * @param {object} params - Notification params. 110 * @return {api.Notification} Added instance (or existing instance if it was already added). 108 * 109 * @param {string|wp.customize.Notification} - Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied. 110 * @param {wp.customize.Notification} [notificationObject] - Notification to add when first argument is the code string. 111 * @returns {wp.customize.Notification} Added notification (or existing instance if it was already added). 111 112 */ 112 add: function( code, params ) { 113 var collection = this; 113 add: function( notification, notificationObject ) { 114 var collection = this, code, instance; 115 if ( 'string' === typeof notification ) { 116 code = notification; 117 instance = notificationObject; 118 } else { 119 code = notification.code; 120 instance = notification; 121 } 114 122 if ( ! collection.has( code ) ) { 115 123 collection._addedIncrement += 1; 116 124 collection._addedOrder[ code ] = collection._addedIncrement; 117 125 } 118 return api.Values.prototype.add.call( this, code, params);126 return api.Values.prototype.add.call( collection, code, instance ); 119 127 }, 120 128 121 129 /** … … 269 277 setting.id = id; 270 278 setting.transport = setting.transport || 'refresh'; 271 279 setting._dirty = options.dirty || false; 272 setting.notifications = new api. Values({ defaultConstructor: api.Notification });280 setting.notifications = new api.Notifications(); 273 281 274 282 // Whenever the setting's value changes, refresh the preview. 275 283 setting.bind( setting.preview ); … … 745 753 * 746 754 * @param {string} id - The ID for the container. 747 755 * @param {object} options - Object containing one property: params. 748 * @param {object} options.params - Object containing the following properties. 749 * @param {string} options.params.title - Title shown when panel is collapsed and expanded. 750 * @param {string=} [options.params.description] - Description shown at the top of the panel. 751 * @param {number=100} [options.params.priority] - The sort priority for the panel. 752 * @param {string=default} [options.params.type] - The type of the panel. See wp.customize.panelConstructor. 753 * @param {string=} [options.params.content] - The markup to be used for the panel container. If empty, a JS template is used. 754 * @param {boolean=true} [options.params.active] - Whether the panel is active or not. 756 * @param {string} options.title - Title shown when panel is collapsed and expanded. 757 * @param {string=} [options.description] - Description shown at the top of the panel. 758 * @param {number=100} [options.priority] - The sort priority for the panel. 759 * @param {string} [options.templateId] - Template selector for container. 760 * @param {string=default} [options.type] - The type of the panel. See wp.customize.panelConstructor. 761 * @param {string=} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. 762 * @param {boolean=true} [options.active] - Whether the panel is active or not. 763 * @param {object} [options.params] - Deprecated wrapper for the above properties. 755 764 */ 756 765 initialize: function ( id, options ) { 757 766 var container = this; 758 767 container.id = id; 759 options = options || {};760 768 761 options.params = _.defaults(762 options.params || {},763 container.defaults764 );769 if ( ! Container.instanceCounter ) { 770 Container.instanceCounter = 0; 771 } 772 Container.instanceCounter++; 765 773 766 $.extend( container, options ); 774 $.extend( container, { 775 params: _.defaults( 776 options.params || options, // Passing the params is deprecated. 777 container.defaults 778 ) 779 } ); 780 if ( ! container.params.instanceNumber ) { 781 container.params.instanceNumber = Container.instanceCounter; 782 } 767 783 container.notifications = new api.Notifications(); 768 container.templateSelector = 'customize-' + container.containerType + '-' + container.params.type;784 container.templateSelector = container.params.templateId || 'customize-' + container.containerType + '-' + container.params.type; 769 785 container.container = $( container.params.content ); 770 786 if ( 0 === container.container.length ) { 771 787 container.container = $( container.getContainer() ); … … 1206 1222 * @since 4.1.0 1207 1223 * 1208 1224 * @param {string} id - The ID for the section. 1209 * @param {object} options - O bject containing one property: params.1210 * @param { object} options.params - Object containing the following properties.1211 * @param {string } options.params.title - Title shown when section is collapsed and expanded.1212 * @param { string=} [options.params.description] - Description shown at the top ofthe section.1213 * @param { number=100} [options.params.priority] - The sort priority for the section.1214 * @param {string= default} [options.params.type] - The type of the section. See wp.customize.sectionConstructor.1215 * @param { string=} [options.params.content] - The markup to be used for the section container. If empty, a JS template is used.1216 * @param { boolean=true} [options.params.active] - Whether the section is active or not.1217 * @param {string } options.params.panel - The ID for the panel this section is associated with.1218 * @param { string=} [options.params.customizeAction] - Additional context information shown before the section title when expanded.1225 * @param {object} options - Options. 1226 * @param {string} options.title - Title shown when section is collapsed and expanded. 1227 * @param {string=} [options.description] - Description shown at the top of the section. 1228 * @param {number=100} [options.priority] - The sort priority for the section. 1229 * @param {string=default} [options.type] - The type of the section. See wp.customize.sectionConstructor. 1230 * @param {string=} [options.content] - The markup to be used for the section container. If empty, a JS template is used. 1231 * @param {boolean=true} [options.active] - Whether the section is active or not. 1232 * @param {string} options.panel - The ID for the panel this section is associated with. 1233 * @param {string=} [options.customizeAction] - Additional context information shown before the section title when expanded. 1234 * @param {object} [options.params] - Deprecated wrapper for the above properties. 1219 1235 */ 1220 1236 initialize: function ( id, options ) { 1221 1237 var section = this; … … 1838 1854 section.container.find( '.no-themes' ).hide(); 1839 1855 request = wp.ajax.post( 'customize_load_themes', params ); 1840 1856 request.done(function( data ) { 1841 var themes = data.themes, themeControl,newThemeControls;1857 var themes = data.themes, newThemeControls; 1842 1858 1843 1859 // Stop and try again if the term changed while loading. 1844 1860 if ( '' !== section.nextTerm || '' !== section.nextTags ) { … … 1860 1876 1861 1877 // Add controls for each theme. 1862 1878 _.each( themes, function( theme ) { 1863 var customizeId = section.params.action + '_theme_' + theme.id; 1864 themeControl = new api.controlConstructor.theme( customizeId, { 1865 params: { 1866 type: 'theme', 1867 content: '<li id="customize-control-theme-' + section.params.action + '_' + theme.id + '" class="customize-control customize-control-theme"></li>', 1868 section: section.params.id, 1869 active: true, 1870 theme: theme, 1871 priority: section.loaded + 1 1872 }, 1873 previewer: api.previewer 1879 var themeControl = new api.controlConstructor.theme( section.params.action + '_theme_' + theme.id, { 1880 type: 'theme', 1881 section: section.params.id, 1882 theme: theme, 1883 priority: section.loaded + 1 1874 1884 } ); 1875 1885 1876 api.control.add( customizeId,themeControl );1886 api.control.add( themeControl ); 1877 1887 newThemeControls.push( themeControl ); 1878 1888 section.loaded = section.loaded + 1; 1879 1889 }); … … 2482 2492 * 2483 2493 * @param {string} id - The ID for the panel. 2484 2494 * @param {object} options - Object containing one property: params. 2485 * @param { object} options.params - Object containing the following properties.2486 * @param {string } options.params.title - Title shown when panel is collapsed and expanded.2487 * @param { string=} [options.params.description] - Description shown at the top ofthe panel.2488 * @param { number=100} [options.params.priority] - The sort priority for the panel.2489 * @param {string= default} [options.params.type] - The type of the panel. See wp.customize.panelConstructor.2490 * @param { string=} [options.params.content] - The markup to be used for the panel container. If empty, a JS template is used.2491 * @param { boolean=true} [options.params.active] - Whether the panel is active or not.2495 * @param {string} options.title - Title shown when panel is collapsed and expanded. 2496 * @param {string=} [options.description] - Description shown at the top of the panel. 2497 * @param {number=100} [options.priority] - The sort priority for the panel. 2498 * @param {string=default} [options.type] - The type of the panel. See wp.customize.panelConstructor. 2499 * @param {string=} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. 2500 * @param {boolean=true} [options.active] - Whether the panel is active or not. 2501 * @param {object} [options.params] - Deprecated wrapper for the above properties. 2492 2502 */ 2493 2503 initialize: function ( id, options ) { 2494 2504 var panel = this; … … 2856 2866 wp.updates.maybeRequestFilesystemCredentials( event ); 2857 2867 2858 2868 $( document ).one( 'wp-theme-install-success', function( event, response ) { 2859 var theme = false, customizeId,themeControl;2869 var theme = false, themeControl; 2860 2870 if ( preview ) { 2861 2871 api.notifications.remove( 'theme_installing' ); 2862 2872 … … 2877 2887 2878 2888 // Add theme control to installed section. 2879 2889 theme.type = 'installed'; 2880 customizeId = 'installed_theme_' + theme.id; 2881 themeControl = new api.controlConstructor.theme( customizeId, { 2882 params: { 2883 type: 'theme', 2884 content: $( '<li class="customize-control customize-control-theme"></li>' ).attr( 'id', 'customize-control-theme-installed_' + theme.id ).prop( 'outerHTML' ), 2885 section: 'installed_themes', 2886 active: true, 2887 theme: theme, 2888 priority: 0 // Add all newly-installed themes to the top. 2889 }, 2890 previewer: api.previewer 2890 themeControl = new api.controlConstructor.theme( 'installed_theme_' + theme.id, { 2891 type: 'theme', 2892 section: 'installed_themes', 2893 theme: theme, 2894 priority: 0 // Add all newly-installed themes to the top. 2891 2895 } ); 2892 2896 2893 api.control.add( customizeId,themeControl );2894 api.control( customizeId ).container.trigger( 'render-screenshot' );2897 api.control.add( themeControl ); 2898 api.control( themeControl.id ).container.trigger( 'render-screenshot' ); 2895 2899 2896 2900 // Close the details modal if it's open to the installed theme. 2897 2901 api.section.each( function( section ) { … … 2913 2917 if ( $( event.target ).hasClass( 'preview' ) ) { 2914 2918 preview = true; 2915 2919 2916 api.notifications.add( 'theme_installing',new api.OverlayNotification( 'theme_installing', {2920 api.notifications.add( new api.OverlayNotification( 'theme_installing', { 2917 2921 message: api.l10n.themeDownloading, 2918 2922 type: 'info', 2919 2923 loading: true … … 2950 2954 urlParser.search = $.param( queryParams ); 2951 2955 2952 2956 // Update loading message. Everything else is handled by reloading the page. 2953 api.notifications.add( 'theme_previewing',new api.OverlayNotification( 'theme_previewing', {2957 api.notifications.add( new api.OverlayNotification( 'theme_previewing', { 2954 2958 message: api.l10n.themePreviewWait, 2955 2959 type: 'info', 2956 2960 loading: true … … 3076 3080 * @class 3077 3081 * @augments wp.customize.Class 3078 3082 * 3079 * @param {string} id Unique identifier for the control instance. 3080 * @param {object} options Options hash for the control instance. 3081 * @param {object} options.params 3082 * @param {object} options.params.type Type of control (e.g. text, radio, dropdown-pages, etc.) 3083 * @param {string} options.params.content The HTML content for the control. 3084 * @param {string} options.params.priority Order of priority to show the control within the section. 3085 * @param {string} options.params.active 3086 * @param {string} options.params.section The ID of the section the control belongs to. 3087 * @param {string} options.params.settings.default The ID of the setting the control relates to. 3088 * @param {string} options.params.settings.data 3089 * @param {string} options.params.label 3090 * @param {string} options.params.description 3091 * @param {string} options.params.instanceNumber Order in which this instance was created in relation to other instances. 3083 * @param {string} id - Unique identifier for the control instance. 3084 * @param {object} options - Options hash for the control instance. 3085 * @param {object} options.type - Type of control (e.g. text, radio, dropdown-pages, etc.) 3086 * @param {string} [options.content] - The HTML content for the control or at least its container. This should normally be left blank and instead supplying a templateId. 3087 * @param {string} [options.templateId] - Template ID for control's content. 3088 * @param {string} [options.priority=10] - Order of priority to show the control within the section. 3089 * @param {string} [options.active=true] - Whether the control is active. 3090 * @param {string} options.section - The ID of the section the control belongs to. 3091 * @param {string} options.settings.default - The ID of the setting the control relates to. 3092 * @param {string} options.settings.data 3093 * @param {string} options.label - Label. 3094 * @param {string} options.description - Description. 3095 * @param {number} [options.instanceNumber] - Order in which this instance was created in relation to other instances. 3096 * @param {object} [options.params] - Deprecated wrapper for the above properties. 3092 3097 */ 3093 3098 api.Control = api.Class.extend({ 3094 3099 defaultActiveArguments: { duration: 'fast', completeCallback: $.noop }, 3095 3100 3101 defaults: { 3102 active: true, 3103 priority: 10 3104 }, 3105 3096 3106 initialize: function( id, options ) { 3097 3107 var control = this, 3098 3108 nodes, radios, settings; 3099 3109 3100 control.params = {}; 3101 $.extend( control, options || {} ); 3110 control.params = _.extend( {}, control.defaults ); 3111 3112 if ( ! api.Control.instanceCounter ) { 3113 api.Control.instanceCounter = 0; 3114 } 3115 api.Control.instanceCounter++; 3116 if ( ! control.params.instanceNumber ) { 3117 control.params.instanceNumber = api.Control.instanceCounter; 3118 } 3119 3120 _.extend( control.params, options.params || options ); 3121 if ( ! control.params.content ) { 3122 control.params.content = $( '<li></li>', { 3123 id: 'customize-control-' + id.replace( /]/g, '' ).replace( /\[/g, '-' ), 3124 'class': 'customize-control customize-control-' + control.params.type 3125 } ); 3126 } 3127 3102 3128 control.id = id; 3103 control.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); 3104 control.templateSelector = 'customize-control-' + control.params.type + '-content'; 3105 control.container = control.params.content ? $( control.params.content ) : $( control.selector ); 3129 control.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); // Deprecated, likely dead code from time before #28709. 3130 control.templateSelector = control.params.templateId || 'customize-control-' + control.params.type + '-content'; 3131 if ( control.params.content ) { 3132 control.container = $( control.params.content ); 3133 } else { 3134 control.container = $( control.selector ); // Likely dead, per above. See #28709. 3135 } 3106 3136 3107 3137 control.deferred = { 3108 3138 embedded: new $.Deferred() … … 3180 3210 // Add setting notifications to the control notification. 3181 3211 _.each( control.settings, function( setting ) { 3182 3212 setting.notifications.bind( 'add', function( settingNotification ) { 3183 var controlNotification, code, params; 3184 code = setting.id + ':' + settingNotification.code; 3185 params = _.extend( 3213 var params = _.extend( 3186 3214 {}, 3187 3215 settingNotification, 3188 3216 { 3189 3217 setting: setting.id 3190 3218 } 3191 3219 ); 3192 controlNotification = new api.Notification( code, params ); 3193 control.notifications.add( controlNotification.code, controlNotification ); 3220 control.notifications.add( new api.Notification( setting.id + ':' + settingNotification.code, params ) ); 3194 3221 } ); 3195 3222 setting.notifications.bind( 'remove', function( settingNotification ) { 3196 3223 control.notifications.remove( setting.id + ':' + settingNotification.code ); … … 3472 3499 */ 3473 3500 _toggleActive: Container.prototype._toggleActive, 3474 3501 3502 // @todo This function appears to be dead code and can be removed. 3475 3503 dropdownInit: function() { 3476 3504 var control = this, 3477 3505 statuses = this.container.find('.dropdown-status'), 3478 3506 params = this.params, 3479 3507 toggleFreeze = false, 3480 3508 update = function( to ) { 3481 if ( typeof to === 'string' && params.statuses && params.statuses[ to ] )3509 if ( 'string' === typeof to && params.statuses && params.statuses[ to ] ) { 3482 3510 statuses.html( params.statuses[ to ] ).show(); 3483 else3511 } else { 3484 3512 statuses.hide(); 3513 } 3485 3514 }; 3486 3515 3487 3516 // Support the .dropdown class to open/close complex elements … … 3492 3521 3493 3522 event.preventDefault(); 3494 3523 3495 if (!toggleFreeze) 3496 control.container.toggleClass('open'); 3524 if ( ! toggleFreeze ) { 3525 control.container.toggleClass( 'open' ); 3526 } 3497 3527 3498 if ( control.container.hasClass('open') ) 3499 control.container.parent().parent().find('li.library-selected').focus(); 3528 if ( control.container.hasClass( 'open' ) ) { 3529 control.container.parent().parent().find( 'li.library-selected' ).focus(); 3530 } 3500 3531 3501 3532 // Don't want to fire focus and click at same time 3502 3533 toggleFreeze = true; … … 4869 4900 } else { 4870 4901 message = api.l10n.customCssError.plural.replace( '%d', String( errorAnnotations.length ) ); 4871 4902 } 4872 control.setting.notifications.add( 'csslint_error',new api.Notification( 'csslint_error', {4903 control.setting.notifications.add( new api.Notification( 'csslint_error', { 4873 4904 message: message, 4874 4905 type: 'error' 4875 4906 } ) ); … … 5256 5287 type: 'error', 5257 5288 message: api.l10n.futureDateError 5258 5289 } ); 5259 control.notifications.add( notification Code, notification);5290 control.notifications.add( notification ); 5260 5291 } else { 5261 5292 control.notifications.remove( notificationCode ); 5262 5293 } … … 5275 5306 */ 5276 5307 api.PreviewLinkControl = api.Control.extend({ 5277 5308 5278 /** 5279 * Override the templateSelector before embedding the control into the page. 5280 * 5281 * @since 4.9.0 5282 * @return {void} 5283 */ 5284 embed: function() { 5285 var control = this; 5286 control.templateSelector = 'customize-preview-link-control'; 5287 return api.Control.prototype.embed.apply( control, arguments ); 5288 }, 5309 defaults: _.extend( {}, api.Control.prototype.defaults, { 5310 templateId: 'customize-preview-link-control' 5311 } ), 5289 5312 5290 5313 /** 5291 5314 * Initialize behaviors. … … 5386 5409 type: 'info', 5387 5410 message: api.l10n.saveBeforeShare 5388 5411 } ); 5389 control.notifications.add( notification Code, notification);5412 control.notifications.add( notification ); 5390 5413 } else { 5391 5414 control.notifications.remove( notificationCode ); 5392 5415 } … … 6014 6037 var previewer = this, 6015 6038 deferred, messenger, iframe; 6016 6039 6017 if ( this._login ) 6040 if ( this._login ) { 6018 6041 return this._login; 6042 } 6019 6043 6020 6044 deferred = $.Deferred(); 6021 6045 this._login = deferred.promise(); … … 6141 6165 } 6142 6166 6143 6167 if ( ! setting.notifications.has( notification.code ) ) { 6144 setting.notifications.add( code,notification );6168 setting.notifications.add( notification ); 6145 6169 } 6146 6170 invalidSettings.push( setting.id ); 6147 6171 } ); … … 6331 6355 footerActions = $( '#customize-footer-actions' ); 6332 6356 6333 6357 api.section( 'publish_settings', function( section ) { 6334 var updateButtonsState, previewLinkControl, TrashControl, trashControlInstance, trashControlId = 'trash_changeset', previewLinkControlId = 'changeset_preview_link', updateSectionActive, isSectionActive;6358 var updateButtonsState, trashControl, updateSectionActive, isSectionActive; 6335 6359 6336 TrashControl = api.Control.extend( { 6337 6338 // This is a temporary hack while waiting for richer JS templating and dynamic instantiation. 6339 embed: function() { 6340 var control = this; 6341 control.templateSelector = 'customize-trash-changeset-control'; 6342 return api.Control.prototype.embed.apply( control, arguments ); 6343 } 6344 } ); 6345 6346 trashControlInstance = new TrashControl( trashControlId, { 6347 params: { 6348 type: 'button', 6349 section: section.id, 6350 active: true, 6351 priority: 30, 6352 content: '<li id="customize-control-' + trashControlId + '" class="customize-control"></li>' 6353 } 6360 trashControl = new api.Control( 'trash_changeset', { 6361 type: 'button', 6362 section: section.id, 6363 priority: 30, 6364 templateId: 'customize-trash-changeset-control' 6354 6365 } ); 6355 api.control.add( trashControl Id, trashControlInstance);6356 trashControl Instance.deferred.embedded.done( function() {6357 trashControl Instance.container.find( 'button' ).on( 'click', function() {6366 api.control.add( trashControl ); 6367 trashControl.deferred.embedded.done( function() { 6368 trashControl.container.find( 'button' ).on( 'click', function() { 6358 6369 if ( confirm( api.l10n.trashConfirm ) ) { 6359 6370 wp.customize.previewer.trash(); 6360 6371 } 6361 6372 } ); 6362 6373 } ); 6363 6374 6364 previewLinkControl = new api.PreviewLinkControl( previewLinkControlId, { 6365 params: { 6366 section: section.id, 6367 active: true, 6368 priority: 100, 6369 content: '<li id="customize-control-' + previewLinkControlId + '" class="customize-control"></li>' 6370 } 6371 } ); 6372 6373 api.control.add( previewLinkControlId, previewLinkControl ); 6375 api.control.add( new api.PreviewLinkControl( 'changeset_preview_link', { 6376 section: section.id, 6377 priority: 100 6378 } ) ); 6374 6379 6375 6380 /** 6376 6381 * Return whether the pubish settings section should be active. … … 6588 6593 api.unbind( 'change', captureSettingModifiedDuringSave ); 6589 6594 6590 6595 if ( invalidSettings.length ) { 6591 api.notifications.add( errorCode,new api.Notification( errorCode, {6596 api.notifications.add( new api.Notification( errorCode, { 6592 6597 message: ( 1 === invalidSettings.length ? api.l10n.saveBlockedError.singular : api.l10n.saveBlockedError.plural ).replace( /%s/g, String( invalidSettings.length ) ), 6593 6598 type: 'error', 6594 6599 dismissible: true, … … 6690 6695 } 6691 6696 6692 6697 if ( notification ) { 6693 api.notifications.add( notification .code, notification);6698 api.notifications.add( notification ); 6694 6699 } 6695 6700 6696 6701 if ( response.setting_validities ) { … … 6795 6800 customize_changeset_uuid: api.settings.changeset.uuid, 6796 6801 nonce: api.settings.nonce.trash 6797 6802 } ); 6798 api.notifications.add( 'changeset_trashing',new api.OverlayNotification( 'changeset_trashing', {6803 api.notifications.add( new api.OverlayNotification( 'changeset_trashing', { 6799 6804 type: 'info', 6800 6805 message: api.l10n.revertingChanges, 6801 6806 loading: true … … 6823 6828 api.state( 'processing' ).set( api.state( 'processing' ).get() - 1 ); 6824 6829 api.state( 'trashing' ).set( false ); 6825 6830 api.notifications.remove( 'changeset_trashing' ); 6826 api.notifications.add( n otificationCode, new api.Notification( notificationCode, {6831 api.notifications.add( new api.Notification( notificationCode, { 6827 6832 message: message || api.l10n.unknownError, 6828 6833 dismissible: true, 6829 6834 type: 'error' … … 6891 6896 6892 6897 // Create Settings 6893 6898 $.each( api.settings.settings, function( id, data ) { 6894 var constructor = api.settingConstructor[ data.type ] || api.Setting, 6895 setting; 6896 6897 setting = new constructor( id, data.value, { 6899 var Constructor = api.settingConstructor[ data.type ] || api.Setting; 6900 api.add( new Constructor( id, data.value, { 6898 6901 transport: data.transport, 6899 6902 previewer: api.previewer, 6900 6903 dirty: !! data.dirty 6901 } ); 6902 api.add( id, setting ); 6904 } ) ); 6903 6905 }); 6904 6906 6905 6907 // Create Panels 6906 6908 $.each( api.settings.panels, function ( id, data ) { 6907 var constructor = api.panelConstructor[ data.type ] || api.Panel, 6908 panel; 6909 6910 panel = new constructor( id, { 6911 params: data 6912 } ); 6913 api.panel.add( id, panel ); 6909 var Constructor = api.panelConstructor[ data.type ] || api.Panel; 6910 api.panel.add( new Constructor( id, data ) ); 6914 6911 }); 6915 6912 6916 6913 // Create Sections 6917 6914 $.each( api.settings.sections, function ( id, data ) { 6918 var constructor = api.sectionConstructor[ data.type ] || api.Section, 6919 section; 6920 6921 section = new constructor( id, { 6922 params: data 6923 } ); 6924 api.section.add( id, section ); 6915 var Constructor = api.sectionConstructor[ data.type ] || api.Section; 6916 api.section.add( new Constructor( id, data ) ); 6925 6917 }); 6926 6918 6927 6919 // Create Controls 6928 6920 $.each( api.settings.controls, function( id, data ) { 6929 var constructor = api.controlConstructor[ data.type ] || api.Control, 6930 control; 6931 6932 control = new constructor( id, { 6933 params: data, 6934 previewer: api.previewer 6935 } ); 6936 api.control.add( id, control ); 6921 var Constructor = api.controlConstructor[ data.type ] || api.Control; 6922 api.control.add( new Constructor( id, data ) ); 6937 6923 }); 6938 6924 6939 6925 // Focus the autofocused element … … 7240 7226 var code = 'autosave_available', onStateChange; 7241 7227 7242 7228 // Since there is an autosave revision and the user hasn't loaded with autosaved, add notification to prompt to load autosaved version. 7243 api.notifications.add( code,new api.Notification( code, {7229 api.notifications.add( new api.Notification( code, { 7244 7230 message: api.l10n.autosaveNotice, 7245 7231 type: 'warning', 7246 7232 dismissible: true, … … 7893 7879 control.element.set( 'blank' !== control.setting() ); 7894 7880 7895 7881 control.element.bind( function( to ) { 7896 if ( ! to ) 7882 if ( ! to ) { 7897 7883 last = api( 'header_textcolor' ).get(); 7884 } 7898 7885 7899 7886 control.setting.set( to ? last : 'blank' ); 7900 7887 }); … … 7926 7913 7927 7914 // Toggle notification when the homepage and posts page are both set and the same. 7928 7915 if ( 'page' === showOnFront() && pageOnFrontId && pageForPostsId && pageOnFrontId === pageForPostsId ) { 7929 showOnFront.notifications.add( errorCode,new api.Notification( errorCode, {7916 showOnFront.notifications.add( new api.Notification( errorCode, { 7930 7917 type: 'error', 7931 7918 message: api.l10n.pageOnFrontError 7932 7919 } ) ); … … 8077 8064 if ( headerVideoControl.active.get() ) { 8078 8065 section.notifications.remove( noticeCode ); 8079 8066 } else { 8080 section.notifications.add( n oticeCode, new api.Notification( noticeCode, {8067 section.notifications.add( new api.Notification( noticeCode, { 8081 8068 type: 'info', 8082 8069 message: api.l10n.videoHeaderNotice 8083 8070 } ) ); -
src/wp-admin/js/customize-nav-menus.js
diff --git src/wp-admin/js/customize-nav-menus.js src/wp-admin/js/customize-nav-menus.js index 4c8447b9fd..258e1bb376 100644
968 968 menuNameControl = api.control( menuNameControlId ); 969 969 if ( ! menuNameControl ) { 970 970 menuNameControl = new api.controlConstructor.nav_menu_name( menuNameControlId, { 971 params: { 972 type: 'nav_menu_name', 973 content: '<li id="customize-control-' + section.id.replace( '[', '-' ).replace( ']', '' ) + '-name" class="customize-control customize-control-nav_menu_name"></li>', // @todo core should do this for us; see #30741 974 label: api.Menus.data.l10n.menuNameLabel, 975 active: true, 976 section: section.id, 977 priority: 0, 978 settings: { 979 'default': section.id 980 } 971 type: 'nav_menu_name', 972 label: api.Menus.data.l10n.menuNameLabel, 973 section: section.id, 974 priority: 0, 975 settings: { 976 'default': section.id 981 977 } 982 978 } ); 983 api.control.add( menuNameControl .id, menuNameControl);979 api.control.add( menuNameControl ); 984 980 menuNameControl.active.set( true ); 985 981 } 986 982 … … 988 984 menuControl = api.control( section.id ); 989 985 if ( ! menuControl ) { 990 986 menuControl = new api.controlConstructor.nav_menu( section.id, { 991 params: { 992 type: 'nav_menu', 993 content: '<li id="customize-control-' + section.id.replace( '[', '-' ).replace( ']', '' ) + '" class="customize-control customize-control-nav_menu"></li>', // @todo core should do this for us; see #30741 994 section: section.id, 995 priority: 998, 996 active: true, 997 settings: { 998 'default': section.id 999 }, 1000 menu_id: section.params.menu_id 1001 } 987 type: 'nav_menu', 988 section: section.id, 989 priority: 998, 990 settings: { 991 'default': section.id 992 }, 993 menu_id: section.params.menu_id 1002 994 } ); 1003 api.control.add( menuControl .id, menuControl);995 api.control.add( menuControl ); 1004 996 menuControl.active.set( true ); 1005 997 } 1006 998 … … 1009 1001 menuAutoAddControl = api.control( menuAutoAddControlId ); 1010 1002 if ( ! menuAutoAddControl ) { 1011 1003 menuAutoAddControl = new api.controlConstructor.nav_menu_auto_add( menuAutoAddControlId, { 1012 params: { 1013 type: 'nav_menu_auto_add', 1014 content: '<li id="customize-control-' + section.id.replace( '[', '-' ).replace( ']', '' ) + '-auto-add" class="customize-control customize-control-nav_menu_auto_add"></li>', // @todo core should do this for us 1015 label: '', 1016 active: true, 1017 section: section.id, 1018 priority: 999, 1019 settings: { 1020 'default': section.id 1021 } 1004 type: 'nav_menu_auto_add', 1005 label: '', 1006 section: section.id, 1007 priority: 999, 1008 settings: { 1009 'default': section.id 1022 1010 } 1023 1011 } ); 1024 api.control.add( menuAutoAddControl .id, menuAutoAddControl);1012 api.control.add( menuAutoAddControl ); 1025 1013 menuAutoAddControl.active.set( true ); 1026 1014 } 1027 1015 … … 2677 2665 2678 2666 // Add the menu item control. 2679 2667 menuItemControl = new api.controlConstructor.nav_menu_item( customizeId, { 2680 params: { 2681 type: 'nav_menu_item', 2682 content: '<li id="customize-control-nav_menu_item-' + String( placeholderId ) + '" class="customize-control customize-control-nav_menu_item"></li>', 2683 section: menuControl.id, 2684 priority: priority, 2685 active: true, 2686 settings: { 2687 'default': customizeId 2688 }, 2689 menu_item_id: placeholderId 2668 type: 'nav_menu_item', 2669 section: menuControl.id, 2670 priority: priority, 2671 settings: { 2672 'default': customizeId 2690 2673 }, 2691 previewer: api.previewer2674 menu_item_id: placeholderId 2692 2675 } ); 2693 2676 2694 api.control.add( customizeId,menuItemControl );2677 api.control.add( menuItemControl ); 2695 2678 setting.preview(); 2696 2679 menuControl.debouncedReflowMenuItems(); 2697 2680 … … 2775 2758 * inside via the Section's ready method. 2776 2759 */ 2777 2760 menuSection = new api.Menus.MenuSection( customizeId, { 2778 params: { 2779 id: customizeId, 2780 panel: 'nav_menus', 2781 title: displayNavMenuName( name ), 2782 customizeAction: api.Menus.data.l10n.customizingMenus, 2783 type: 'nav_menu', 2784 priority: 10, 2785 menu_id: placeholderId 2786 } 2761 panel: 'nav_menus', 2762 title: displayNavMenuName( name ), 2763 customizeAction: api.Menus.data.l10n.customizingMenus, 2764 type: 'nav_menu', 2765 priority: 10, 2766 menu_id: placeholderId 2787 2767 } ); 2788 api.section.add( customizeId,menuSection );2768 api.section.add( menuSection ); 2789 2769 2790 2770 // Clear name field. 2791 2771 nameInput.val( '' ); … … 2909 2889 2910 2890 // Add the menu section. 2911 2891 newSection = new api.Menus.MenuSection( newCustomizeId, { 2912 params: { 2913 id: newCustomizeId, 2914 panel: 'nav_menus', 2915 title: settingValue.name, 2916 customizeAction: api.Menus.data.l10n.customizingMenus, 2917 type: 'nav_menu', 2918 priority: oldSection.priority.get(), 2919 active: true, 2920 menu_id: update.term_id 2921 } 2892 panel: 'nav_menus', 2893 title: settingValue.name, 2894 customizeAction: api.Menus.data.l10n.customizingMenus, 2895 type: 'nav_menu', 2896 priority: oldSection.priority.get(), 2897 menu_id: update.term_id 2922 2898 } ); 2923 2899 2924 2900 // Add new control for the new menu. 2925 api.section.add( new CustomizeId, newSection );2901 api.section.add( newSection ); 2926 2902 2927 2903 // Update the values for nav menus in Custom Menu controls. 2928 2904 api.control.each( function( setting ) { … … 3052 3028 3053 3029 // Add the menu control. 3054 3030 newControl = new api.controlConstructor.nav_menu_item( newCustomizeId, { 3055 params: { 3056 type: 'nav_menu_item', 3057 content: '<li id="customize-control-nav_menu_item-' + String( update.post_id ) + '" class="customize-control customize-control-nav_menu_item"></li>', 3058 menu_id: update.post_id, 3059 section: 'nav_menu[' + String( settingValue.nav_menu_term_id ) + ']', 3060 priority: oldControl.priority.get(), 3061 active: true, 3062 settings: { 3063 'default': newCustomizeId 3064 }, 3065 menu_item_id: update.post_id 3031 type: 'nav_menu_item', 3032 menu_id: update.post_id, 3033 section: 'nav_menu[' + String( settingValue.nav_menu_term_id ) + ']', 3034 priority: oldControl.priority.get(), 3035 settings: { 3036 'default': newCustomizeId 3066 3037 }, 3067 previewer: api.previewer3038 menu_item_id: update.post_id 3068 3039 } ); 3069 3040 3070 3041 // Remove old control. … … 3072 3043 api.control.remove( oldCustomizeId ); 3073 3044 3074 3045 // Add new control to take its place. 3075 api.control.add( newC ustomizeId, newControl );3046 api.control.add( newControl ); 3076 3047 3077 3048 // Delete the placeholder and preview the new setting. 3078 3049 oldSetting.callbacks.disable(); // Prevent setting triggering Customizer dirty state when set. -
src/wp-admin/js/customize-widgets.js
diff --git src/wp-admin/js/customize-widgets.js src/wp-admin/js/customize-widgets.js index dc46d73410..b8f6d7a8c6 100644
2098 2098 2099 2099 controlConstructor = api.controlConstructor[controlType]; 2100 2100 widgetFormControl = new controlConstructor( settingId, { 2101 params: { 2102 settings: { 2103 'default': settingId 2104 }, 2105 content: controlContainer, 2106 sidebar_id: self.params.sidebar_id, 2107 widget_id: widgetId, 2108 widget_id_base: widget.get( 'id_base' ), 2109 type: controlType, 2110 is_new: ! isExistingWidget, 2111 width: widget.get( 'width' ), 2112 height: widget.get( 'height' ), 2113 is_wide: widget.get( 'is_wide' ), 2114 active: true 2101 settings: { 2102 'default': settingId 2115 2103 }, 2116 previewer: self.setting.previewer 2104 content: controlContainer, 2105 sidebar_id: self.params.sidebar_id, 2106 widget_id: widgetId, 2107 widget_id_base: widget.get( 'id_base' ), 2108 type: controlType, 2109 is_new: ! isExistingWidget, 2110 width: widget.get( 'width' ), 2111 height: widget.get( 'height' ), 2112 is_wide: widget.get( 'is_wide' ) 2117 2113 } ); 2118 api.control.add( settingId,widgetFormControl );2114 api.control.add( widgetFormControl ); 2119 2115 2120 2116 // Make sure widget is removed from the other sidebars 2121 2117 api.each( function( otherSetting ) { -
src/wp-includes/class-wp-customize-manager.php
diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php index eba2143a2c..873b093dfc 100644
final class WP_Customize_Manager { 3604 3604 3605 3605 ?> 3606 3606 <script type="text/html" id="tmpl-customize-notification"> 3607 <li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.dismissible ? 'is-dismissible' : '' }} {{ data.c lasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}">3607 <li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.dismissible ? 'is-dismissible' : '' }} {{ data.containerClasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}"> 3608 3608 <div class="notification-message">{{{ data.message || data.code }}}</div> 3609 3609 <# if ( data.dismissible ) { #> 3610 3610 <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php _e( 'Dismiss' ); ?></span></button> -
src/wp-includes/js/customize-base.js
diff --git src/wp-includes/js/customize-base.js src/wp-includes/js/customize-base.js index 7db5084ada..3b943a61be 100644
window.wp = window.wp || {}; 376 376 /** 377 377 * Add an item to the collection. 378 378 * 379 * @param {string } id The ID of the item.380 * @param { mixed} value The item instance.381 * @return { mixed} The new item's instance.379 * @param {string|wp.customize.Class} item - The item instance to add, or the ID for the instance to add. When an ID string is supplied, then itemObject must be provided. 380 * @param {wp.customize.Class} [itemObject] - The item instance when the first argument is a ID string. 381 * @return {wp.customize.Class} The new item's instance, or an existing instance if already added. 382 382 */ 383 add: function( id, value ) { 384 if ( this.has( id ) ) 385 return this.value( id ); 383 add: function( item, itemObject ) { 384 var collection = this, id, instance; 385 if ( 'string' === typeof item ) { 386 id = item; 387 instance = itemObject; 388 } else { 389 if ( 'string' !== typeof item.id ) { 390 throw new Error( 'Unknown key' ); 391 } 392 id = item.id; 393 instance = item; 394 } 386 395 387 this._value[ id ] = value; 388 value.parent = this; 396 if ( collection.has( id ) ) { 397 return collection.value( id ); 398 } 399 400 collection._value[ id ] = instance; 401 instance.parent = collection; 389 402 390 403 // Propagate a 'change' event on an item up to the collection. 391 if ( value.extended( api.Value ) ) 392 value.bind( this._change ); 404 if ( instance.extended( api.Value ) ) { 405 instance.bind( collection._change ); 406 } 393 407 394 this.trigger( 'add', value );408 collection.trigger( 'add', instance ); 395 409 396 410 // If a deferred object exists for this item, 397 411 // resolve it. 398 if ( this._deferreds[ id ] ) 399 this._deferreds[ id ].resolve(); 412 if ( collection._deferreds[ id ] ) { 413 collection._deferreds[ id ].resolve(); 414 } 400 415 401 return this._value[ id ];416 return collection._value[ id ]; 402 417 }, 403 418 404 419 /** … … window.wp = window.wp || {}; 815 830 * @since 4.9.0 816 831 * @var {string} 817 832 */ 818 c lasses: '',833 containerClasses: '', 819 834 820 835 /** 821 836 * Initialize notification. … … window.wp = window.wp || {}; 829 844 * @param {string} [params.setting] - Related setting ID. 830 845 * @param {Function} [params.template] - Function for rendering template. If not provided, this will come from templateId. 831 846 * @param {string} [params.templateId] - ID for template to render the notification. 832 * @param {string} [params.c lasses] - Additional class names to add to the notification container.847 * @param {string} [params.containerClasses] - Additional class names to add to the notification container. 833 848 * @param {boolean} [params.dismissible] - Whether the notification can be dismissed. 834 849 */ 835 850 initialize: function( code, params ) { … … window.wp = window.wp || {}; 844 859 setting: null, 845 860 template: null, 846 861 dismissible: false, 847 c lasses: ''862 containerClasses: '' 848 863 }, 849 864 params 850 865 ); -
src/wp-includes/js/customize-preview-widgets.js
diff --git src/wp-includes/js/customize-preview-widgets.js src/wp-includes/js/customize-preview-widgets.js index b981788ed3..b2a60d892c 100644
wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( 407 407 wasInserted = true; 408 408 } ); 409 409 410 api.selectiveRefresh.partial.add( widgetPartial .id, widgetPartial);410 api.selectiveRefresh.partial.add( widgetPartial ); 411 411 412 412 if ( wasInserted ) { 413 413 sidebarPartial.reflowWidgets(); … … wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( 510 510 sidebarArgs: registeredSidebar 511 511 } 512 512 } ); 513 api.selectiveRefresh.partial.add( partial .id, partial);513 api.selectiveRefresh.partial.add( partial ); 514 514 } 515 515 } ); 516 516 }; -
src/wp-includes/js/customize-selective-refresh.js
diff --git src/wp-includes/js/customize-selective-refresh.js src/wp-includes/js/customize-selective-refresh.js index 62bcfd8de0..3da7c0a237 100644
wp.customize.selectiveRefresh = ( function( $, api ) { 877 877 partialOptions.constructingContainerContext = containerElement.data( 'customize-partial-placement-context' ) || {}; 878 878 Constructor = self.partialConstructor[ containerElement.data( 'customize-partial-type' ) ] || self.Partial; 879 879 partial = new Constructor( id, partialOptions ); 880 self.partial.add( partial .id, partial);880 self.partial.add( partial ); 881 881 } 882 882 883 883 /* … … wp.customize.selectiveRefresh = ( function( $, api ) { 918 918 if ( ! partial ) { 919 919 Constructor = self.partialConstructor[ data.type ] || self.Partial; 920 920 partial = new Constructor( id, { params: data } ); 921 self.partial.add( id,partial );921 self.partial.add( partial ); 922 922 } else { 923 923 _.extend( partial.params, data ); 924 924 } -
tests/qunit/wp-admin/js/customize-controls.js
diff --git tests/qunit/wp-admin/js/customize-controls.js tests/qunit/wp-admin/js/customize-controls.js index 32b48127a2..dc3e391121 100644
jQuery( window ).load( function (){ 306 306 type: 'default', 307 307 content: null, 308 308 active: true, 309 instanceNumber: null,310 309 customizeAction: '' 311 310 }; 312 311 jQuery.each( defaultParams, function ( key, value ) { 313 312 ok( 'undefined' !== typeof section.params[ key ] ); 314 313 equal( value, section.params[ key ] ); 315 314 } ); 315 ok( _.isNumber( section.params.instanceNumber ) ); 316 316 } ); 317 317 318 318 … … jQuery( window ).load( function (){ 417 417 priority: 100, 418 418 type: 'default', 419 419 content: null, 420 active: true, 421 instanceNumber: null 420 active: true 422 421 }; 423 422 jQuery.each( defaultParams, function ( key, value ) { 424 423 ok( 'undefined' !== typeof panel.params[ key ] ); 425 424 equal( value, panel.params[ key ] ); 426 425 } ); 426 ok( _.isNumber( panel.params.instanceNumber ) ); 427 427 } ); 428 428 429 429 module( 'Dynamically-created Customizer Setting Model' );