23 * @augments wp.customize.Notification |
23 * @augments wp.customize.Notification |
24 * |
24 * |
25 * @since 4.9.0 |
25 * @since 4.9.0 |
26 * |
26 * |
27 * @param {string} code - Code. |
27 * @param {string} code - Code. |
28 * @param {object} params - Params. |
28 * @param {Object} params - Params. |
29 */ |
29 */ |
30 initialize: function( code, params ) { |
30 initialize: function( code, params ) { |
31 var notification = this; |
31 var notification = this; |
32 api.Notification.prototype.initialize.call( notification, code, params ); |
32 api.Notification.prototype.initialize.call( notification, code, params ); |
33 notification.containerClasses += ' notification-overlay'; |
33 notification.containerClasses += ' notification-overlay'; |
92 * @since 4.9.0 |
92 * @since 4.9.0 |
93 * |
93 * |
94 * @constructs wp.customize.Notifications |
94 * @constructs wp.customize.Notifications |
95 * @augments wp.customize.Values |
95 * @augments wp.customize.Values |
96 * |
96 * |
97 * @param {object} options - Options. |
97 * @param {Object} options - Options. |
98 * @param {jQuery} [options.container] - Container element for notifications. This can be injected later. |
98 * @param {jQuery} [options.container] - Container element for notifications. This can be injected later. |
99 * @param {boolean} [options.alt] - Whether alternative style should be used when rendering notifications. |
99 * @param {boolean} [options.alt] - Whether alternative style should be used when rendering notifications. |
100 * |
100 * |
101 * @returns {void} |
101 * @return {void} |
102 */ |
102 */ |
103 initialize: function( options ) { |
103 initialize: function( options ) { |
104 var collection = this; |
104 var collection = this; |
105 |
105 |
106 api.Values.prototype.initialize.call( collection, options ); |
106 api.Values.prototype.initialize.call( collection, options ); |
135 * |
135 * |
136 * @since 4.9.0 |
136 * @since 4.9.0 |
137 * |
137 * |
138 * @param {string|wp.customize.Notification} notification - Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied. |
138 * @param {string|wp.customize.Notification} notification - Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied. |
139 * @param {wp.customize.Notification} [notificationObject] - Notification to add when first argument is the code string. |
139 * @param {wp.customize.Notification} [notificationObject] - Notification to add when first argument is the code string. |
140 * @returns {wp.customize.Notification} Added notification (or existing instance if it was already added). |
140 * @return {wp.customize.Notification} Added notification (or existing instance if it was already added). |
141 */ |
141 */ |
142 add: function( notification, notificationObject ) { |
142 add: function( notification, notificationObject ) { |
143 var collection = this, code, instance; |
143 var collection = this, code, instance; |
144 if ( 'string' === typeof notification ) { |
144 if ( 'string' === typeof notification ) { |
145 code = notification; |
145 code = notification; |
172 * Get list of notifications. |
172 * Get list of notifications. |
173 * |
173 * |
174 * Notifications may be sorted by type followed by added time. |
174 * Notifications may be sorted by type followed by added time. |
175 * |
175 * |
176 * @since 4.9.0 |
176 * @since 4.9.0 |
177 * @param {object} args - Args. |
177 * @param {Object} args - Args. |
178 * @param {boolean} [args.sort=false] - Whether to return the notifications sorted. |
178 * @param {boolean} [args.sort=false] - Whether to return the notifications sorted. |
179 * @return {Array.<wp.customize.Notification>} Notifications. |
179 * @return {Array.<wp.customize.Notification>} Notifications. |
180 */ |
180 */ |
181 get: function( args ) { |
181 get: function( args ) { |
182 var collection = this, notifications, errorTypePriorities, params; |
182 var collection = this, notifications, errorTypePriorities, params; |
360 * |
360 * |
361 * @since 3.4.0 |
361 * @since 3.4.0 |
362 * |
362 * |
363 * @param {string} id - The setting ID. |
363 * @param {string} id - The setting ID. |
364 * @param {*} value - The initial value of the setting. |
364 * @param {*} value - The initial value of the setting. |
365 * @param {object} [options={}] - Options. |
365 * @param {Object} [options={}] - Options. |
366 * @param {string} [options.transport=refresh] - The transport to use for previewing. Supports 'refresh' and 'postMessage'. |
366 * @param {string} [options.transport=refresh] - The transport to use for previewing. Supports 'refresh' and 'postMessage'. |
367 * @param {boolean} [options.dirty=false] - Whether the setting should be considered initially dirty. |
367 * @param {boolean} [options.dirty=false] - Whether the setting should be considered initially dirty. |
368 * @param {object} [options.previewer] - The Previewer instance to sync with. Defaults to wp.customize.previewer. |
368 * @param {Object} [options.previewer] - The Previewer instance to sync with. Defaults to wp.customize.previewer. |
369 */ |
369 */ |
370 initialize: function( id, value, options ) { |
370 initialize: function( id, value, options ) { |
371 var setting = this, params; |
371 var setting = this, params; |
372 params = _.extend( |
372 params = _.extend( |
373 { previewer: api.previewer }, |
373 { previewer: api.previewer }, |
526 * @alias wp.customize.requestChangesetUpdate |
526 * @alias wp.customize.requestChangesetUpdate |
527 * |
527 * |
528 * @since 4.7.0 |
528 * @since 4.7.0 |
529 * @access public |
529 * @access public |
530 * |
530 * |
531 * @param {object} [changes] - Mapping of setting IDs to setting params each normally including a value property, or mapping to null. |
531 * @param {Object} [changes] - Mapping of setting IDs to setting params each normally including a value property, or mapping to null. |
532 * If not provided, then the changes will still be obtained from unsaved dirty settings. |
532 * If not provided, then the changes will still be obtained from unsaved dirty settings. |
533 * @param {object} [args] - Additional options for the save request. |
533 * @param {Object} [args] - Additional options for the save request. |
534 * @param {boolean} [args.autosave=false] - Whether changes will be stored in autosave revision if the changeset has been promoted from an auto-draft. |
534 * @param {boolean} [args.autosave=false] - Whether changes will be stored in autosave revision if the changeset has been promoted from an auto-draft. |
535 * @param {boolean} [args.force=false] - Send request to update even when there are no changes to submit. This can be used to request the latest status of the changeset on the server. |
535 * @param {boolean} [args.force=false] - Send request to update even when there are no changes to submit. This can be used to request the latest status of the changeset on the server. |
536 * @param {string} [args.title] - Title to update in the changeset. Optional. |
536 * @param {string} [args.title] - Title to update in the changeset. Optional. |
537 * @param {string} [args.date] - Date to update in the changeset. Optional. |
537 * @param {string} [args.date] - Date to update in the changeset. Optional. |
538 * @returns {jQuery.Promise} Promise resolving with the response data. |
538 * @return {jQuery.Promise} Promise resolving with the response data. |
539 */ |
539 */ |
540 api.requestChangesetUpdate = function requestChangesetUpdate( changes, args ) { |
540 api.requestChangesetUpdate = function requestChangesetUpdate( changes, args ) { |
541 var deferred, request, submittedChanges = {}, data, submittedArgs; |
541 var deferred, request, submittedChanges = {}, data, submittedArgs; |
542 deferred = new $.Deferred(); |
542 deferred = new $.Deferred(); |
543 |
543 |
576 if ( ! submittedArgs.force && _.isEmpty( submittedChanges ) && null === submittedArgs.title && null === submittedArgs.date ) { |
576 if ( ! submittedArgs.force && _.isEmpty( submittedChanges ) && null === submittedArgs.title && null === submittedArgs.date ) { |
577 deferred.resolve( {} ); |
577 deferred.resolve( {} ); |
578 return deferred.promise(); |
578 return deferred.promise(); |
579 } |
579 } |
580 |
580 |
581 // A status would cause a revision to be made, and for this wp.customize.previewer.save() should be used. Status is also disallowed for revisions regardless. |
581 // A status would cause a revision to be made, and for this wp.customize.previewer.save() should be used. |
|
582 // Status is also disallowed for revisions regardless. |
582 if ( submittedArgs.status ) { |
583 if ( submittedArgs.status ) { |
583 return deferred.reject( { code: 'illegal_status_in_changeset_update' } ).promise(); |
584 return deferred.reject( { code: 'illegal_status_in_changeset_update' } ).promise(); |
584 } |
585 } |
585 |
586 |
586 // Dates not beung allowed for revisions are is a technical limitation of post revisions. |
587 // Dates not beung allowed for revisions are is a technical limitation of post revisions. |
766 * |
767 * |
767 * @since 4.1.0 |
768 * @since 4.1.0 |
768 * |
769 * |
769 * @param {Array|jQuery} listA |
770 * @param {Array|jQuery} listA |
770 * @param {Array|jQuery} listB |
771 * @param {Array|jQuery} listB |
771 * @returns {boolean} |
772 * @return {boolean} |
772 */ |
773 */ |
773 api.utils.areElementListsEqual = function ( listA, listB ) { |
774 api.utils.areElementListsEqual = function ( listA, listB ) { |
774 var equal = ( |
775 var equal = ( |
775 listA.length === listB.length && // if lists are different lengths, then naturally they are not equal |
776 listA.length === listB.length && // If lists are different lengths, then naturally they are not equal. |
776 -1 === _.indexOf( _.map( // are there any false values in the list returned by map? |
777 -1 === _.indexOf( _.map( // Are there any false values in the list returned by map? |
777 _.zip( listA, listB ), // pair up each element between the two lists |
778 _.zip( listA, listB ), // Pair up each element between the two lists. |
778 function ( pair ) { |
779 function ( pair ) { |
779 return $( pair[0] ).is( pair[1] ); // compare to see if each pair are equal |
780 return $( pair[0] ).is( pair[1] ); // Compare to see if each pair is equal. |
780 } |
781 } |
781 ), false ) // check for presence of false in map's return value |
782 ), false ) // Check for presence of false in map's return value. |
782 ); |
783 ); |
783 return equal; |
784 return equal; |
784 }; |
785 }; |
785 |
786 |
786 /** |
787 /** |
793 * @alias wp.customize.utils.highlightButton |
794 * @alias wp.customize.utils.highlightButton |
794 * |
795 * |
795 * @since 4.9.0 |
796 * @since 4.9.0 |
796 * |
797 * |
797 * @param {jQuery} button - The element to highlight. |
798 * @param {jQuery} button - The element to highlight. |
798 * @param {object} [options] - Options. |
799 * @param {Object} [options] - Options. |
799 * @param {number} [options.delay=0] - Delay in milliseconds. |
800 * @param {number} [options.delay=0] - Delay in milliseconds. |
800 * @param {jQuery} [options.focusTarget] - A target for user focus that defaults to the highlighted element. |
801 * @param {jQuery} [options.focusTarget] - A target for user focus that defaults to the highlighted element. |
801 * If the user focuses the target before the delay passes, the reminder |
802 * If the user focuses the target before the delay passes, the reminder |
802 * is canceled. This option exists to accommodate compound buttons |
803 * is canceled. This option exists to accommodate compound buttons |
803 * containing auxiliary UI, such as the Publish button augmented with a |
804 * containing auxiliary UI, such as the Publish button augmented with a |
804 * Settings button. |
805 * Settings button. |
805 * @returns {Function} An idempotent function that cancels the reminder. |
806 * @return {Function} An idempotent function that cancels the reminder. |
806 */ |
807 */ |
807 api.utils.highlightButton = function highlightButton( button, options ) { |
808 api.utils.highlightButton = function highlightButton( button, options ) { |
808 var animationClass = 'button-see-me', |
809 var animationClass = 'button-see-me', |
809 canceled = false, |
810 canceled = false, |
810 params; |
811 params; |
866 * |
867 * |
867 * @alias wp.customize.utils.getRemainingTime |
868 * @alias wp.customize.utils.getRemainingTime |
868 * |
869 * |
869 * @since 4.9.0 |
870 * @since 4.9.0 |
870 * |
871 * |
871 * @param {string|int|Date} datetime - Date time or timestamp of the future date. |
872 * @param {string|number|Date} datetime - Date time or timestamp of the future date. |
872 * @return {int} remainingTime - Remaining time in milliseconds. |
873 * @return {number} remainingTime - Remaining time in milliseconds. |
873 */ |
874 */ |
874 api.utils.getRemainingTime = function getRemainingTime( datetime ) { |
875 api.utils.getRemainingTime = function getRemainingTime( datetime ) { |
875 var millisecondsDivider = 1000, remainingTime, timestamp; |
876 var millisecondsDivider = 1000, remainingTime, timestamp; |
876 if ( datetime instanceof Date ) { |
877 if ( datetime instanceof Date ) { |
877 timestamp = datetime.getTime(); |
878 timestamp = datetime.getTime(); |
937 * @since 4.1.0 |
938 * @since 4.1.0 |
938 * |
939 * |
939 * @borrows wp.customize~focus as focus |
940 * @borrows wp.customize~focus as focus |
940 * |
941 * |
941 * @param {string} id - The ID for the container. |
942 * @param {string} id - The ID for the container. |
942 * @param {object} options - Object containing one property: params. |
943 * @param {Object} options - Object containing one property: params. |
943 * @param {string} options.title - Title shown when panel is collapsed and expanded. |
944 * @param {string} options.title - Title shown when panel is collapsed and expanded. |
944 * @param {string} [options.description] - Description shown at the top of the panel. |
945 * @param {string} [options.description] - Description shown at the top of the panel. |
945 * @param {number} [options.priority=100] - The sort priority for the panel. |
946 * @param {number} [options.priority=100] - The sort priority for the panel. |
946 * @param {string} [options.templateId] - Template selector for container. |
947 * @param {string} [options.templateId] - Template selector for container. |
947 * @param {string} [options.type=default] - The type of the panel. See wp.customize.panelConstructor. |
948 * @param {string} [options.type=default] - The type of the panel. See wp.customize.panelConstructor. |
948 * @param {string} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. |
949 * @param {string} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. |
949 * @param {boolean} [options.active=true] - Whether the panel is active or not. |
950 * @param {boolean} [options.active=true] - Whether the panel is active or not. |
950 * @param {object} [options.params] - Deprecated wrapper for the above properties. |
951 * @param {Object} [options.params] - Deprecated wrapper for the above properties. |
951 */ |
952 */ |
952 initialize: function ( id, options ) { |
953 initialize: function ( id, options ) { |
953 var container = this; |
954 var container = this; |
954 container.id = id; |
955 container.id = id; |
955 |
956 |
1012 |
1013 |
1013 /** |
1014 /** |
1014 * Get the element that will contain the notifications. |
1015 * Get the element that will contain the notifications. |
1015 * |
1016 * |
1016 * @since 4.9.0 |
1017 * @since 4.9.0 |
1017 * @returns {jQuery} Notification container element. |
1018 * @return {jQuery} Notification container element. |
1018 */ |
1019 */ |
1019 getNotificationsContainerElement: function() { |
1020 getNotificationsContainerElement: function() { |
1020 var container = this; |
1021 var container = this; |
1021 return container.contentContainer.find( '.customize-control-notifications-container:first' ); |
1022 return container.contentContainer.find( '.customize-control-notifications-container:first' ); |
1022 }, |
1023 }, |
1023 |
1024 |
1024 /** |
1025 /** |
1025 * Set up notifications. |
1026 * Set up notifications. |
1026 * |
1027 * |
1027 * @since 4.9.0 |
1028 * @since 4.9.0 |
1028 * @returns {void} |
1029 * @return {void} |
1029 */ |
1030 */ |
1030 setupNotifications: function() { |
1031 setupNotifications: function() { |
1031 var container = this, renderNotifications; |
1032 var container = this, renderNotifications; |
1032 container.notifications.container = container.getNotificationsContainerElement(); |
1033 container.notifications.container = container.getNotificationsContainerElement(); |
1033 |
1034 |
1171 } |
1173 } |
1172 }, |
1174 }, |
1173 |
1175 |
1174 /** |
1176 /** |
1175 * @param {Object} [params] |
1177 * @param {Object} [params] |
1176 * @returns {Boolean} false if already active |
1178 * @return {boolean} False if already active. |
1177 */ |
1179 */ |
1178 activate: function ( params ) { |
1180 activate: function ( params ) { |
1179 return this._toggleActive( true, params ); |
1181 return this._toggleActive( true, params ); |
1180 }, |
1182 }, |
1181 |
1183 |
1182 /** |
1184 /** |
1183 * @param {Object} [params] |
1185 * @param {Object} [params] |
1184 * @returns {Boolean} false if already inactive |
1186 * @return {boolean} False if already inactive. |
1185 */ |
1187 */ |
1186 deactivate: function ( params ) { |
1188 deactivate: function ( params ) { |
1187 return this._toggleActive( false, params ); |
1189 return this._toggleActive( false, params ); |
1188 }, |
1190 }, |
1189 |
1191 |
1196 }, |
1198 }, |
1197 |
1199 |
1198 /** |
1200 /** |
1199 * Handle the toggle logic for expand/collapse. |
1201 * Handle the toggle logic for expand/collapse. |
1200 * |
1202 * |
1201 * @param {Boolean} expanded - The new state to apply. |
1203 * @param {boolean} expanded - The new state to apply. |
1202 * @param {Object} [params] - Object containing options for expand/collapse. |
1204 * @param {Object} [params] - Object containing options for expand/collapse. |
1203 * @param {Function} [params.completeCallback] - Function to call when expansion/collapse is complete. |
1205 * @param {Function} [params.completeCallback] - Function to call when expansion/collapse is complete. |
1204 * @returns {Boolean} false if state already applied or active state is false |
1206 * @return {boolean} False if state already applied or active state is false. |
1205 */ |
1207 */ |
1206 _toggleExpanded: function( expanded, params ) { |
1208 _toggleExpanded: function( expanded, params ) { |
1207 var instance = this, previousCompleteCallback; |
1209 var instance = this, previousCompleteCallback; |
1208 params = params || {}; |
1210 params = params || {}; |
1209 previousCompleteCallback = params.completeCallback; |
1211 previousCompleteCallback = params.completeCallback; |
1236 } |
1238 } |
1237 }, |
1239 }, |
1238 |
1240 |
1239 /** |
1241 /** |
1240 * @param {Object} [params] |
1242 * @param {Object} [params] |
1241 * @returns {Boolean} false if already expanded or if inactive. |
1243 * @return {boolean} False if already expanded or if inactive. |
1242 */ |
1244 */ |
1243 expand: function ( params ) { |
1245 expand: function ( params ) { |
1244 return this._toggleExpanded( true, params ); |
1246 return this._toggleExpanded( true, params ); |
1245 }, |
1247 }, |
1246 |
1248 |
1247 /** |
1249 /** |
1248 * @param {Object} [params] |
1250 * @param {Object} [params] |
1249 * @returns {Boolean} false if already collapsed. |
1251 * @return {boolean} False if already collapsed. |
1250 */ |
1252 */ |
1251 collapse: function ( params ) { |
1253 collapse: function ( params ) { |
1252 return this._toggleExpanded( false, params ); |
1254 return this._toggleExpanded( false, params ); |
1253 }, |
1255 }, |
1254 |
1256 |
1405 * @augments wp.customize~Container |
1407 * @augments wp.customize~Container |
1406 * |
1408 * |
1407 * @since 4.1.0 |
1409 * @since 4.1.0 |
1408 * |
1410 * |
1409 * @param {string} id - The ID for the section. |
1411 * @param {string} id - The ID for the section. |
1410 * @param {object} options - Options. |
1412 * @param {Object} options - Options. |
1411 * @param {string} options.title - Title shown when section is collapsed and expanded. |
1413 * @param {string} options.title - Title shown when section is collapsed and expanded. |
1412 * @param {string} [options.description] - Description shown at the top of the section. |
1414 * @param {string} [options.description] - Description shown at the top of the section. |
1413 * @param {number} [options.priority=100] - The sort priority for the section. |
1415 * @param {number} [options.priority=100] - The sort priority for the section. |
1414 * @param {string} [options.type=default] - The type of the section. See wp.customize.sectionConstructor. |
1416 * @param {string} [options.type=default] - The type of the section. See wp.customize.sectionConstructor. |
1415 * @param {string} [options.content] - The markup to be used for the section container. If empty, a JS template is used. |
1417 * @param {string} [options.content] - The markup to be used for the section container. If empty, a JS template is used. |
1416 * @param {boolean} [options.active=true] - Whether the section is active or not. |
1418 * @param {boolean} [options.active=true] - Whether the section is active or not. |
1417 * @param {string} options.panel - The ID for the panel this section is associated with. |
1419 * @param {string} options.panel - The ID for the panel this section is associated with. |
1418 * @param {string} [options.customizeAction] - Additional context information shown before the section title when expanded. |
1420 * @param {string} [options.customizeAction] - Additional context information shown before the section title when expanded. |
1419 * @param {object} [options.params] - Deprecated wrapper for the above properties. |
1421 * @param {Object} [options.params] - Deprecated wrapper for the above properties. |
1420 */ |
1422 */ |
1421 initialize: function ( id, options ) { |
1423 initialize: function ( id, options ) { |
1422 var section = this, params; |
1424 var section = this, params; |
1423 params = options.params || options; |
1425 params = options.params || options; |
1424 |
1426 |
1560 /** |
1562 /** |
1561 * Get the controls that are associated with this section, sorted by their priority Value. |
1563 * Get the controls that are associated with this section, sorted by their priority Value. |
1562 * |
1564 * |
1563 * @since 4.1.0 |
1565 * @since 4.1.0 |
1564 * |
1566 * |
1565 * @returns {Array} |
1567 * @return {Array} |
1566 */ |
1568 */ |
1567 controls: function () { |
1569 controls: function () { |
1568 return this._children( 'section', 'control' ); |
1570 return this._children( 'section', 'control' ); |
1569 }, |
1571 }, |
1570 |
1572 |
1571 /** |
1573 /** |
1572 * Update UI to reflect expanded state. |
1574 * Update UI to reflect expanded state. |
1573 * |
1575 * |
1574 * @since 4.1.0 |
1576 * @since 4.1.0 |
1575 * |
1577 * |
1576 * @param {Boolean} expanded |
1578 * @param {boolean} expanded |
1577 * @param {Object} args |
1579 * @param {Object} args |
1578 */ |
1580 */ |
1579 onChangeExpanded: function ( expanded, args ) { |
1581 onChangeExpanded: function ( expanded, args ) { |
1580 var section = this, |
1582 var section = this, |
1581 container = section.headContainer.closest( '.wp-full-overlay-sidebar-content' ), |
1583 container = section.headContainer.closest( '.wp-full-overlay-sidebar-content' ), |
1716 */ |
1718 */ |
1717 embed: function() { |
1719 embed: function() { |
1718 var inject, |
1720 var inject, |
1719 section = this; |
1721 section = this; |
1720 |
1722 |
1721 // Watch for changes to the panel state |
1723 // Watch for changes to the panel state. |
1722 inject = function( panelId ) { |
1724 inject = function( panelId ) { |
1723 var parentContainer; |
1725 var parentContainer; |
1724 api.panel( panelId, function( panel ) { |
1726 api.panel( panelId, function( panel ) { |
1725 |
1727 |
1726 // The panel has been registered, wait for it to become ready/initialized |
1728 // The panel has been registered, wait for it to become ready/initialized. |
1727 panel.deferred.embedded.done( function() { |
1729 panel.deferred.embedded.done( function() { |
1728 parentContainer = panel.contentContainer; |
1730 parentContainer = panel.contentContainer; |
1729 if ( ! section.headContainer.parent().is( parentContainer ) ) { |
1731 if ( ! section.headContainer.parent().is( parentContainer ) ) { |
1730 parentContainer.find( '.customize-themes-full-container-container' ).before( section.headContainer ); |
1732 parentContainer.find( '.customize-themes-full-container-container' ).before( section.headContainer ); |
1731 } |
1733 } |
1756 section.container.on( 'keydown', function( event ) { |
1758 section.container.on( 'keydown', function( event ) { |
1757 if ( ! section.overlay.find( '.theme-wrap' ).is( ':visible' ) ) { |
1759 if ( ! section.overlay.find( '.theme-wrap' ).is( ':visible' ) ) { |
1758 return; |
1760 return; |
1759 } |
1761 } |
1760 |
1762 |
1761 // Pressing the right arrow key fires a theme:next event |
1763 // Pressing the right arrow key fires a theme:next event. |
1762 if ( 39 === event.keyCode ) { |
1764 if ( 39 === event.keyCode ) { |
1763 section.nextTheme(); |
1765 section.nextTheme(); |
1764 } |
1766 } |
1765 |
1767 |
1766 // Pressing the left arrow key fires a theme:previous event |
1768 // Pressing the left arrow key fires a theme:previous event. |
1767 if ( 37 === event.keyCode ) { |
1769 if ( 37 === event.keyCode ) { |
1768 section.previousTheme(); |
1770 section.previousTheme(); |
1769 } |
1771 } |
1770 |
1772 |
1771 // Pressing the escape key fires a theme:collapse event |
1773 // Pressing the escape key fires a theme:collapse event. |
1772 if ( 27 === event.keyCode ) { |
1774 if ( 27 === event.keyCode ) { |
1773 if ( section.$body.hasClass( 'modal-open' ) ) { |
1775 if ( section.$body.hasClass( 'modal-open' ) ) { |
1774 |
1776 |
1775 // Escape from the details modal. |
1777 // Escape from the details modal. |
1776 section.closeDetails(); |
1778 section.closeDetails(); |
1795 * use the section's own active state instead. This prevents empty search |
1797 * use the section's own active state instead. This prevents empty search |
1796 * results for theme sections from causing the section to become inactive. |
1798 * results for theme sections from causing the section to become inactive. |
1797 * |
1799 * |
1798 * @since 4.2.0 |
1800 * @since 4.2.0 |
1799 * |
1801 * |
1800 * @returns {Boolean} |
1802 * @return {boolean} |
1801 */ |
1803 */ |
1802 isContextuallyActive: function () { |
1804 isContextuallyActive: function () { |
1803 return this.active(); |
1805 return this.active(); |
1804 }, |
1806 }, |
1805 |
1807 |
1806 /** |
1808 /** |
1807 * Attach events. |
1809 * Attach events. |
1808 * |
1810 * |
1809 * @since 4.2.0 |
1811 * @since 4.2.0 |
1810 * |
1812 * |
1811 * @returns {void} |
1813 * @return {void} |
1812 */ |
1814 */ |
1813 attachEvents: function () { |
1815 attachEvents: function () { |
1814 var section = this, debounced; |
1816 var section = this, debounced; |
1815 |
1817 |
1816 // Expand/Collapse accordion sections on click. |
1818 // Expand/Collapse accordion sections on click. |
1817 section.container.find( '.customize-section-back' ).on( 'click keydown', function( event ) { |
1819 section.container.find( '.customize-section-back' ).on( 'click keydown', function( event ) { |
1818 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { |
1820 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { |
1819 return; |
1821 return; |
1820 } |
1822 } |
1821 event.preventDefault(); // Keep this AFTER the key filter above |
1823 event.preventDefault(); // Keep this AFTER the key filter above. |
1822 section.collapse(); |
1824 section.collapse(); |
1823 }); |
1825 }); |
1824 |
1826 |
1825 section.headerContainer = $( '#accordion-section-' + section.id ); |
1827 section.headerContainer = $( '#accordion-section-' + section.id ); |
1826 |
1828 |
1947 /** |
1949 /** |
1948 * Update UI to reflect expanded state |
1950 * Update UI to reflect expanded state |
1949 * |
1951 * |
1950 * @since 4.2.0 |
1952 * @since 4.2.0 |
1951 * |
1953 * |
1952 * @param {Boolean} expanded |
1954 * @param {boolean} expanded |
1953 * @param {Object} args |
1955 * @param {Object} args |
1954 * @param {Boolean} args.unchanged |
1956 * @param {boolean} args.unchanged |
1955 * @param {Function} args.completeCallback |
1957 * @param {Function} args.completeCallback |
1956 * @returns {void} |
1958 * @return {void} |
1957 */ |
1959 */ |
1958 onChangeExpanded: function ( expanded, args ) { |
1960 onChangeExpanded: function ( expanded, args ) { |
1959 |
1961 |
1960 // Note: there is a second argument 'args' passed |
1962 // Note: there is a second argument 'args' passed. |
1961 var section = this, |
1963 var section = this, |
1962 container = section.contentContainer.closest( '.customize-themes-full-container' ); |
1964 container = section.contentContainer.closest( '.customize-themes-full-container' ); |
1963 |
1965 |
1964 // Immediately call the complete callback if there were no changes |
1966 // Immediately call the complete callback if there were no changes. |
1965 if ( args.unchanged ) { |
1967 if ( args.unchanged ) { |
1966 if ( args.completeCallback ) { |
1968 if ( args.completeCallback ) { |
1967 args.completeCallback(); |
1969 args.completeCallback(); |
1968 } |
1970 } |
1969 return; |
1971 return; |
2192 |
2195 |
2193 /** |
2196 /** |
2194 * Determines whether more themes should be loaded, and loads them. |
2197 * Determines whether more themes should be loaded, and loads them. |
2195 * |
2198 * |
2196 * @since 4.9.0 |
2199 * @since 4.9.0 |
2197 * @returns {void} |
2200 * @return {void} |
2198 */ |
2201 */ |
2199 loadMore: function() { |
2202 loadMore: function() { |
2200 var section = this, container, bottom, threshold; |
2203 var section = this, container, bottom, threshold; |
2201 if ( ! section.fullyLoaded && ! section.loading ) { |
2204 if ( ! section.fullyLoaded && ! section.loading ) { |
2202 container = section.container.closest( '.customize-themes-full-container' ); |
2205 container = section.container.closest( '.customize-themes-full-container' ); |
2203 |
2206 |
2204 bottom = container.scrollTop() + container.height(); |
2207 bottom = container.scrollTop() + container.height(); |
2205 threshold = container.prop( 'scrollHeight' ) - 3000; // Use a fixed distance to the bottom of loaded results to avoid unnecessarily loading results sooner when using a percentage of scroll distance. |
2208 // Use a fixed distance to the bottom of loaded results to avoid unnecessarily |
|
2209 // loading results sooner when using a percentage of scroll distance. |
|
2210 threshold = container.prop( 'scrollHeight' ) - 3000; |
2206 |
2211 |
2207 if ( bottom > threshold ) { |
2212 if ( bottom > threshold ) { |
2208 section.loadThemes(); |
2213 section.loadThemes(); |
2209 } |
2214 } |
2210 } |
2215 } |
2405 /** |
2410 /** |
2406 * Get visible count. |
2411 * Get visible count. |
2407 * |
2412 * |
2408 * @since 4.9.0 |
2413 * @since 4.9.0 |
2409 * |
2414 * |
2410 * @returns {int} Visible count. |
2415 * @return {number} Visible count. |
2411 */ |
2416 */ |
2412 getVisibleCount: function() { |
2417 getVisibleCount: function() { |
2413 return this.contentContainer.find( 'li.customize-control:visible' ).length; |
2418 return this.contentContainer.find( 'li.customize-control:visible' ).length; |
2414 }, |
2419 }, |
2415 |
2420 |
2416 /** |
2421 /** |
2417 * Update the number of themes in the section. |
2422 * Update the number of themes in the section. |
2418 * |
2423 * |
2419 * @since 4.9.0 |
2424 * @since 4.9.0 |
2420 * |
2425 * |
2421 * @returns {void} |
2426 * @return {void} |
2422 */ |
2427 */ |
2423 updateCount: function( count ) { |
2428 updateCount: function( count ) { |
2424 var section = this, countEl, displayed; |
2429 var section = this, countEl, displayed; |
2425 |
2430 |
2426 if ( ! count && 0 !== count ) { |
2431 if ( ! count && 0 !== count ) { |
2499 |
2504 |
2500 /** |
2505 /** |
2501 * Get the previous theme model. |
2506 * Get the previous theme model. |
2502 * |
2507 * |
2503 * @since 4.2.0 |
2508 * @since 4.2.0 |
2504 * @returns {wp.customize.ThemeControl|boolean} Previous theme. |
2509 * @return {wp.customize.ThemeControl|boolean} Previous theme. |
2505 */ |
2510 */ |
2506 getPreviousTheme: function () { |
2511 getPreviousTheme: function () { |
2507 var section = this, control, nextControl, sectionControls, i; |
2512 var section = this, control, nextControl, sectionControls, i; |
2508 control = api.control( section.params.action + '_theme_' + section.currentTheme ); |
2513 control = api.control( section.params.action + '_theme_' + section.currentTheme ); |
2509 sectionControls = section.controls(); |
2514 sectionControls = section.controls(); |
2541 * @since 4.7.0 |
2546 * @since 4.7.0 |
2542 * @access public |
2547 * @access public |
2543 * |
2548 * |
2544 * @deprecated |
2549 * @deprecated |
2545 * @param {string} themeId Theme ID. |
2550 * @param {string} themeId Theme ID. |
2546 * @returns {jQuery.promise} Promise. |
2551 * @return {jQuery.promise} Promise. |
2547 */ |
2552 */ |
2548 loadThemePreview: function( themeId ) { |
2553 loadThemePreview: function( themeId ) { |
2549 return api.ThemesPanel.prototype.loadThemePreview.call( this, themeId ); |
2554 return api.ThemesPanel.prototype.loadThemePreview.call( this, themeId ); |
2550 }, |
2555 }, |
2551 |
2556 |
2552 /** |
2557 /** |
2553 * Render & show the theme details for a given theme model. |
2558 * Render & show the theme details for a given theme model. |
2554 * |
2559 * |
2555 * @since 4.2.0 |
2560 * @since 4.2.0 |
2556 * |
2561 * |
2557 * @param {object} theme - Theme. |
2562 * @param {Object} theme - Theme. |
2558 * @param {Function} [callback] - Callback once the details have been shown. |
2563 * @param {Function} [callback] - Callback once the details have been shown. |
2559 * @returns {void} |
2564 * @return {void} |
2560 */ |
2565 */ |
2561 showDetails: function ( theme, callback ) { |
2566 showDetails: function ( theme, callback ) { |
2562 var section = this, panel = api.panel( 'themes' ); |
2567 var section = this, panel = api.panel( 'themes' ); |
2563 section.currentTheme = theme.id; |
2568 section.currentTheme = theme.id; |
2564 section.overlay.html( section.template( theme ) ) |
2569 section.overlay.html( section.template( theme ) ) |
2604 * Keep tab focus within the theme details modal. |
2609 * Keep tab focus within the theme details modal. |
2605 * |
2610 * |
2606 * @since 4.2.0 |
2611 * @since 4.2.0 |
2607 * |
2612 * |
2608 * @param {jQuery} el - Element to contain focus. |
2613 * @param {jQuery} el - Element to contain focus. |
2609 * @returns {void} |
2614 * @return {void} |
2610 */ |
2615 */ |
2611 containFocus: function( el ) { |
2616 containFocus: function( el ) { |
2612 var tabbables; |
2617 var tabbables; |
2613 |
2618 |
2614 el.on( 'keydown', function( event ) { |
2619 el.on( 'keydown', function( event ) { |
2615 |
2620 |
2616 // Return if it's not the tab key |
2621 // Return if it's not the tab key |
2617 // When navigating with prev/next focus is already handled |
2622 // When navigating with prev/next focus is already handled. |
2618 if ( 9 !== event.keyCode ) { |
2623 if ( 9 !== event.keyCode ) { |
2619 return; |
2624 return; |
2620 } |
2625 } |
2621 |
2626 |
2622 // uses jQuery UI to get the tabbable elements |
2627 // Uses jQuery UI to get the tabbable elements. |
2623 tabbables = $( ':tabbable', el ); |
2628 tabbables = $( ':tabbable', el ); |
2624 |
2629 |
2625 // Keep focus within the overlay |
2630 // Keep focus within the overlay. |
2626 if ( tabbables.last()[0] === event.target && ! event.shiftKey ) { |
2631 if ( tabbables.last()[0] === event.target && ! event.shiftKey ) { |
2627 tabbables.first().focus(); |
2632 tabbables.first().focus(); |
2628 return false; |
2633 return false; |
2629 } else if ( tabbables.first()[0] === event.target && event.shiftKey ) { |
2634 } else if ( tabbables.first()[0] === event.target && event.shiftKey ) { |
2630 tabbables.last().focus(); |
2635 tabbables.last().focus(); |
2660 * Overrides api.Section.prototype.onChangeExpanded to prevent collapse/expand effect |
2665 * Overrides api.Section.prototype.onChangeExpanded to prevent collapse/expand effect |
2661 * on other sections and panels. |
2666 * on other sections and panels. |
2662 * |
2667 * |
2663 * @since 4.9.0 |
2668 * @since 4.9.0 |
2664 * |
2669 * |
2665 * @param {Boolean} expanded - The expanded state to transition to. |
2670 * @param {boolean} expanded - The expanded state to transition to. |
2666 * @param {Object} [args] - Args. |
2671 * @param {Object} [args] - Args. |
2667 * @param {boolean} [args.unchanged] - Whether the state is already known to not be changed, and so short-circuit with calling completeCallback early. |
2672 * @param {boolean} [args.unchanged] - Whether the state is already known to not be changed, and so short-circuit with calling completeCallback early. |
2668 * @param {Function} [args.completeCallback] - Function to call when the slideUp/slideDown has completed. |
2673 * @param {Function} [args.completeCallback] - Function to call when the slideUp/slideDown has completed. |
2669 * @param {Object} [args.duration] - The duration for the animation. |
2674 * @param {Object} [args.duration] - The duration for the animation. |
2670 */ |
2675 */ |
2755 * @augments wp.customize~Container |
2760 * @augments wp.customize~Container |
2756 * |
2761 * |
2757 * @since 4.1.0 |
2762 * @since 4.1.0 |
2758 * |
2763 * |
2759 * @param {string} id - The ID for the panel. |
2764 * @param {string} id - The ID for the panel. |
2760 * @param {object} options - Object containing one property: params. |
2765 * @param {Object} options - Object containing one property: params. |
2761 * @param {string} options.title - Title shown when panel is collapsed and expanded. |
2766 * @param {string} options.title - Title shown when panel is collapsed and expanded. |
2762 * @param {string} [options.description] - Description shown at the top of the panel. |
2767 * @param {string} [options.description] - Description shown at the top of the panel. |
2763 * @param {number} [options.priority=100] - The sort priority for the panel. |
2768 * @param {number} [options.priority=100] - The sort priority for the panel. |
2764 * @param {string} [options.type=default] - The type of the panel. See wp.customize.panelConstructor. |
2769 * @param {string} [options.type=default] - The type of the panel. See wp.customize.panelConstructor. |
2765 * @param {string} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. |
2770 * @param {string} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. |
2766 * @param {boolean} [options.active=true] - Whether the panel is active or not. |
2771 * @param {boolean} [options.active=true] - Whether the panel is active or not. |
2767 * @param {object} [options.params] - Deprecated wrapper for the above properties. |
2772 * @param {Object} [options.params] - Deprecated wrapper for the above properties. |
2768 */ |
2773 */ |
2769 initialize: function ( id, options ) { |
2774 initialize: function ( id, options ) { |
2770 var panel = this, params; |
2775 var panel = this, params; |
2771 params = options.params || options; |
2776 params = options.params || options; |
2772 |
2777 |
2868 /** |
2873 /** |
2869 * Get the sections that are associated with this panel, sorted by their priority Value. |
2874 * Get the sections that are associated with this panel, sorted by their priority Value. |
2870 * |
2875 * |
2871 * @since 4.1.0 |
2876 * @since 4.1.0 |
2872 * |
2877 * |
2873 * @returns {Array} |
2878 * @return {Array} |
2874 */ |
2879 */ |
2875 sections: function () { |
2880 sections: function () { |
2876 return this._children( 'panel', 'section' ); |
2881 return this._children( 'panel', 'section' ); |
2877 }, |
2882 }, |
2878 |
2883 |
2879 /** |
2884 /** |
2880 * Return whether this panel has any active sections. |
2885 * Return whether this panel has any active sections. |
2881 * |
2886 * |
2882 * @since 4.1.0 |
2887 * @since 4.1.0 |
2883 * |
2888 * |
2884 * @returns {boolean} Whether contextually active. |
2889 * @return {boolean} Whether contextually active. |
2885 */ |
2890 */ |
2886 isContextuallyActive: function () { |
2891 isContextuallyActive: function () { |
2887 var panel = this, |
2892 var panel = this, |
2888 sections = panel.sections(), |
2893 sections = panel.sections(), |
2889 activeCount = 0; |
2894 activeCount = 0; |
2898 /** |
2903 /** |
2899 * Update UI to reflect expanded state. |
2904 * Update UI to reflect expanded state. |
2900 * |
2905 * |
2901 * @since 4.1.0 |
2906 * @since 4.1.0 |
2902 * |
2907 * |
2903 * @param {Boolean} expanded |
2908 * @param {boolean} expanded |
2904 * @param {Object} args |
2909 * @param {Object} args |
2905 * @param {Boolean} args.unchanged |
2910 * @param {boolean} args.unchanged |
2906 * @param {Function} args.completeCallback |
2911 * @param {Function} args.completeCallback |
2907 * @returns {void} |
2912 * @return {void} |
2908 */ |
2913 */ |
2909 onChangeExpanded: function ( expanded, args ) { |
2914 onChangeExpanded: function ( expanded, args ) { |
2910 |
2915 |
2911 // Immediately call the complete callback if there were no changes |
2916 // Immediately call the complete callback if there were no changes. |
2912 if ( args.unchanged ) { |
2917 if ( args.unchanged ) { |
2913 if ( args.completeCallback ) { |
2918 if ( args.completeCallback ) { |
2914 args.completeCallback(); |
2919 args.completeCallback(); |
2915 } |
2920 } |
2916 return; |
2921 return; |
2917 } |
2922 } |
2918 |
2923 |
2919 // Note: there is a second argument 'args' passed |
2924 // Note: there is a second argument 'args' passed. |
2920 var panel = this, |
2925 var panel = this, |
2921 accordionSection = panel.contentContainer, |
2926 accordionSection = panel.contentContainer, |
2922 overlay = accordionSection.closest( '.wp-full-overlay' ), |
2927 overlay = accordionSection.closest( '.wp-full-overlay' ), |
2923 container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ), |
2928 container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ), |
2924 topPanel = panel.headContainer.find( '.accordion-section-title' ), |
2929 topPanel = panel.headContainer.find( '.accordion-section-title' ), |
2925 backBtn = accordionSection.find( '.customize-panel-back' ), |
2930 backBtn = accordionSection.find( '.customize-panel-back' ), |
2926 childSections = panel.sections(), |
2931 childSections = panel.sections(), |
2927 skipTransition; |
2932 skipTransition; |
2928 |
2933 |
2929 if ( expanded && ! accordionSection.hasClass( 'current-panel' ) ) { |
2934 if ( expanded && ! accordionSection.hasClass( 'current-panel' ) ) { |
2930 // Collapse any sibling sections/panels |
2935 // Collapse any sibling sections/panels. |
2931 api.section.each( function ( section ) { |
2936 api.section.each( function ( section ) { |
2932 if ( panel.id !== section.panel() ) { |
2937 if ( panel.id !== section.panel() ) { |
2933 section.collapse( { duration: 0 } ); |
2938 section.collapse( { duration: 0 } ); |
2934 } |
2939 } |
2935 }); |
2940 }); |
3057 |
3062 |
3058 /** |
3063 /** |
3059 * Attach events. |
3064 * Attach events. |
3060 * |
3065 * |
3061 * @since 4.9.0 |
3066 * @since 4.9.0 |
3062 * @returns {void} |
3067 * @return {void} |
3063 */ |
3068 */ |
3064 attachEvents: function() { |
3069 attachEvents: function() { |
3065 var panel = this; |
3070 var panel = this; |
3066 |
3071 |
3067 // Attach regular panel events. |
3072 // Attach regular panel events. |
3068 api.Panel.prototype.attachEvents.apply( panel ); |
3073 api.Panel.prototype.attachEvents.apply( panel ); |
3069 |
3074 |
3070 // Temporary since supplying SFTP credentials does not work yet. See #42184 |
3075 // Temporary since supplying SFTP credentials does not work yet. See #42184. |
3071 if ( api.settings.theme._canInstall && api.settings.theme._filesystemCredentialsNeeded ) { |
3076 if ( api.settings.theme._canInstall && api.settings.theme._filesystemCredentialsNeeded ) { |
3072 panel.notifications.add( new api.Notification( 'theme_install_unavailable', { |
3077 panel.notifications.add( new api.Notification( 'theme_install_unavailable', { |
3073 message: api.l10n.themeInstallUnavailable, |
3078 message: api.l10n.themeInstallUnavailable, |
3074 type: 'info', |
3079 type: 'info', |
3075 dismissible: true |
3080 dismissible: true |
3126 /** |
3131 /** |
3127 * Update UI to reflect expanded state |
3132 * Update UI to reflect expanded state |
3128 * |
3133 * |
3129 * @since 4.9.0 |
3134 * @since 4.9.0 |
3130 * |
3135 * |
3131 * @param {Boolean} expanded - Expanded state. |
3136 * @param {boolean} expanded - Expanded state. |
3132 * @param {Object} args - Args. |
3137 * @param {Object} args - Args. |
3133 * @param {Boolean} args.unchanged - Whether or not the state changed. |
3138 * @param {boolean} args.unchanged - Whether or not the state changed. |
3134 * @param {Function} args.completeCallback - Callback to execute when the animation completes. |
3139 * @param {Function} args.completeCallback - Callback to execute when the animation completes. |
3135 * @returns {void} |
3140 * @return {void} |
3136 */ |
3141 */ |
3137 onChangeExpanded: function( expanded, args ) { |
3142 onChangeExpanded: function( expanded, args ) { |
3138 var panel = this, overlay, sections, hasExpandedSection = false; |
3143 var panel = this, overlay, sections, hasExpandedSection = false; |
3139 |
3144 |
3140 // Expand/collapse the panel normally. |
3145 // Expand/collapse the panel normally. |
3141 api.Panel.prototype.onChangeExpanded.apply( this, [ expanded, args ] ); |
3146 api.Panel.prototype.onChangeExpanded.apply( this, [ expanded, args ] ); |
3142 |
3147 |
3143 // Immediately call the complete callback if there were no changes |
3148 // Immediately call the complete callback if there were no changes. |
3144 if ( args.unchanged ) { |
3149 if ( args.unchanged ) { |
3145 if ( args.completeCallback ) { |
3150 if ( args.completeCallback ) { |
3146 args.completeCallback(); |
3151 args.completeCallback(); |
3147 } |
3152 } |
3148 return; |
3153 return; |
3182 * Install a theme via wp.updates. |
3187 * Install a theme via wp.updates. |
3183 * |
3188 * |
3184 * @since 4.9.0 |
3189 * @since 4.9.0 |
3185 * |
3190 * |
3186 * @param {jQuery.Event} event - Event. |
3191 * @param {jQuery.Event} event - Event. |
3187 * @returns {jQuery.promise} Promise. |
3192 * @return {jQuery.promise} Promise. |
3188 */ |
3193 */ |
3189 installTheme: function( event ) { |
3194 installTheme: function( event ) { |
3190 var panel = this, preview, onInstallSuccess, slug = $( event.target ).data( 'slug' ), deferred = $.Deferred(), request; |
3195 var panel = this, preview, onInstallSuccess, slug = $( event.target ).data( 'slug' ), deferred = $.Deferred(), request; |
3191 preview = $( event.target ).hasClass( 'preview' ); |
3196 preview = $( event.target ).hasClass( 'preview' ); |
3192 |
3197 |
3287 * Load theme preview. |
3292 * Load theme preview. |
3288 * |
3293 * |
3289 * @since 4.9.0 |
3294 * @since 4.9.0 |
3290 * |
3295 * |
3291 * @param {string} themeId Theme ID. |
3296 * @param {string} themeId Theme ID. |
3292 * @returns {jQuery.promise} Promise. |
3297 * @return {jQuery.promise} Promise. |
3293 */ |
3298 */ |
3294 loadThemePreview: function( themeId ) { |
3299 loadThemePreview: function( themeId ) { |
3295 var panel = this, deferred = $.Deferred(), onceProcessingComplete, urlParser, queryParams; |
3300 var panel = this, deferred = $.Deferred(), onceProcessingComplete, urlParser, queryParams; |
3296 |
3301 |
3297 // Prevent loading a non-active theme preview when there is a drafted/scheduled changeset. |
3302 // Prevent loading a non-active theme preview when there is a drafted/scheduled changeset. |
3475 * @borrows wp.customize~Container#activate as this#activate |
3480 * @borrows wp.customize~Container#activate as this#activate |
3476 * @borrows wp.customize~Container#deactivate as this#deactivate |
3481 * @borrows wp.customize~Container#deactivate as this#deactivate |
3477 * @borrows wp.customize~Container#_toggleActive as this#_toggleActive |
3482 * @borrows wp.customize~Container#_toggleActive as this#_toggleActive |
3478 * |
3483 * |
3479 * @param {string} id - Unique identifier for the control instance. |
3484 * @param {string} id - Unique identifier for the control instance. |
3480 * @param {object} options - Options hash for the control instance. |
3485 * @param {Object} options - Options hash for the control instance. |
3481 * @param {object} options.type - Type of control (e.g. text, radio, dropdown-pages, etc.) |
3486 * @param {Object} options.type - Type of control (e.g. text, radio, dropdown-pages, etc.) |
3482 * @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. |
3487 * @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. |
3483 * @param {string} [options.templateId] - Template ID for control's content. |
3488 * @param {string} [options.templateId] - Template ID for control's content. |
3484 * @param {string} [options.priority=10] - Order of priority to show the control within the section. |
3489 * @param {string} [options.priority=10] - Order of priority to show the control within the section. |
3485 * @param {string} [options.active=true] - Whether the control is active. |
3490 * @param {string} [options.active=true] - Whether the control is active. |
3486 * @param {string} options.section - The ID of the section the control belongs to. |
3491 * @param {string} options.section - The ID of the section the control belongs to. |
3489 * @param {mixed} options.settings.default - The ID of the setting the control relates to. |
3494 * @param {mixed} options.settings.default - The ID of the setting the control relates to. |
3490 * @param {string} options.settings.data - @todo Is this used? |
3495 * @param {string} options.settings.data - @todo Is this used? |
3491 * @param {string} options.label - Label. |
3496 * @param {string} options.label - Label. |
3492 * @param {string} options.description - Description. |
3497 * @param {string} options.description - Description. |
3493 * @param {number} [options.instanceNumber] - Order in which this instance was created in relation to other instances. |
3498 * @param {number} [options.instanceNumber] - Order in which this instance was created in relation to other instances. |
3494 * @param {object} [options.params] - Deprecated wrapper for the above properties. |
3499 * @param {Object} [options.params] - Deprecated wrapper for the above properties. |
3495 * @returns {void} |
3500 * @return {void} |
3496 */ |
3501 */ |
3497 initialize: function( id, options ) { |
3502 initialize: function( id, options ) { |
3498 var control = this, deferredSettingIds = [], settings, gatherSettings; |
3503 var control = this, deferredSettingIds = [], settings, gatherSettings; |
3499 |
3504 |
3500 control.params = _.extend( |
3505 control.params = _.extend( |
3501 {}, |
3506 {}, |
3502 control.defaults, |
3507 control.defaults, |
3503 control.params || {}, // In case sub-class already defines. |
3508 control.params || {}, // In case subclass already defines. |
3504 options.params || options || {} // The options.params property is deprecated, but it is checked first for back-compat. |
3509 options.params || options || {} // The options.params property is deprecated, but it is checked first for back-compat. |
3505 ); |
3510 ); |
3506 |
3511 |
3507 if ( ! api.Control.instanceCounter ) { |
3512 if ( ! api.Control.instanceCounter ) { |
3508 api.Control.instanceCounter = 0; |
3513 api.Control.instanceCounter = 0; |
3680 */ |
3685 */ |
3681 embed: function () { |
3686 embed: function () { |
3682 var control = this, |
3687 var control = this, |
3683 inject; |
3688 inject; |
3684 |
3689 |
3685 // Watch for changes to the section state |
3690 // Watch for changes to the section state. |
3686 inject = function ( sectionId ) { |
3691 inject = function ( sectionId ) { |
3687 var parentContainer; |
3692 var parentContainer; |
3688 if ( ! sectionId ) { // @todo allow a control to be embedded without a section, for instance a control embedded in the front end. |
3693 if ( ! sectionId ) { // @todo Allow a control to be embedded without a section, for instance a control embedded in the front end. |
3689 return; |
3694 return; |
3690 } |
3695 } |
3691 // Wait for the section to be registered |
3696 // Wait for the section to be registered. |
3692 api.section( sectionId, function ( section ) { |
3697 api.section( sectionId, function ( section ) { |
3693 // Wait for the section to be ready/initialized |
3698 // Wait for the section to be ready/initialized. |
3694 section.deferred.embedded.done( function () { |
3699 section.deferred.embedded.done( function () { |
3695 parentContainer = ( section.contentContainer.is( 'ul' ) ) ? section.contentContainer : section.contentContainer.find( 'ul:first' ); |
3700 parentContainer = ( section.contentContainer.is( 'ul' ) ) ? section.contentContainer : section.contentContainer.find( 'ul:first' ); |
3696 if ( ! control.container.parent().is( parentContainer ) ) { |
3701 if ( ! control.container.parent().is( parentContainer ) ) { |
3697 parentContainer.append( control.container ); |
3702 parentContainer.append( control.container ); |
3698 control.renderContent(); |
3703 control.renderContent(); |
3737 * Control subclasses may override this to return the proper container to render notifications into. |
3742 * Control subclasses may override this to return the proper container to render notifications into. |
3738 * Injects the notification container for existing controls that lack the necessary container, |
3743 * Injects the notification container for existing controls that lack the necessary container, |
3739 * including special handling for nav menu items and widgets. |
3744 * including special handling for nav menu items and widgets. |
3740 * |
3745 * |
3741 * @since 4.6.0 |
3746 * @since 4.6.0 |
3742 * @returns {jQuery} Setting validation message element. |
3747 * @return {jQuery} Setting validation message element. |
3743 */ |
3748 */ |
3744 getNotificationsContainerElement: function() { |
3749 getNotificationsContainerElement: function() { |
3745 var control = this, controlTitle, notificationsContainer; |
3750 var control = this, controlTitle, notificationsContainer; |
3746 |
3751 |
3747 notificationsContainer = control.container.find( '.customize-control-notifications-container:first' ); |
3752 notificationsContainer = control.container.find( '.customize-control-notifications-container:first' ); |
3893 * This does not change the active state, it merely handles the behavior |
3898 * This does not change the active state, it merely handles the behavior |
3894 * for when it does change. |
3899 * for when it does change. |
3895 * |
3900 * |
3896 * @since 4.1.0 |
3901 * @since 4.1.0 |
3897 * |
3902 * |
3898 * @param {Boolean} active |
3903 * @param {boolean} active |
3899 * @param {Object} args |
3904 * @param {Object} args |
3900 * @param {Number} args.duration |
3905 * @param {number} args.duration |
3901 * @param {Function} args.completeCallback |
3906 * @param {Function} args.completeCallback |
3902 */ |
3907 */ |
3903 onChangeActive: function ( active, args ) { |
3908 onChangeActive: function ( active, args ) { |
3904 if ( args.unchanged ) { |
3909 if ( args.unchanged ) { |
3905 if ( args.completeCallback ) { |
3910 if ( args.completeCallback ) { |
4015 'url' |
4020 'url' |
4016 ]; |
4021 ]; |
4017 |
4022 |
4018 templateId = control.templateSelector; |
4023 templateId = control.templateSelector; |
4019 |
4024 |
4020 // Use default content template when a standard HTML type is used, there isn't a more specific template existing, and the control container is empty. |
4025 // Use default content template when a standard HTML type is used, |
|
4026 // there isn't a more specific template existing, and the control container is empty. |
4021 if ( templateId === 'customize-control-' + control.params.type + '-content' && |
4027 if ( templateId === 'customize-control-' + control.params.type + '-content' && |
4022 _.contains( standardTypes, control.params.type ) && |
4028 _.contains( standardTypes, control.params.type ) && |
4023 ! document.getElementById( 'tmpl-' + templateId ) && |
4029 ! document.getElementById( 'tmpl-' + templateId ) && |
4024 0 === control.container.children().length ) |
4030 0 === control.container.children().length ) |
4025 { |
4031 { |
4197 control.container.on( 'click keydown', '.default-button', control.restoreDefault ); |
4205 control.container.on( 'click keydown', '.default-button', control.restoreDefault ); |
4198 control.container.on( 'click keydown', '.remove-button', control.pausePlayer ); |
4206 control.container.on( 'click keydown', '.remove-button', control.pausePlayer ); |
4199 control.container.on( 'click keydown', '.remove-button', control.removeFile ); |
4207 control.container.on( 'click keydown', '.remove-button', control.removeFile ); |
4200 control.container.on( 'click keydown', '.remove-button', control.cleanupPlayer ); |
4208 control.container.on( 'click keydown', '.remove-button', control.cleanupPlayer ); |
4201 |
4209 |
4202 // Resize the player controls when it becomes visible (ie when section is expanded) |
4210 // Resize the player controls when it becomes visible (ie when section is expanded). |
4203 api.section( control.section() ).container |
4211 api.section( control.section() ).container |
4204 .on( 'expanded', function() { |
4212 .on( 'expanded', function() { |
4205 if ( control.player ) { |
4213 if ( control.player ) { |
4206 control.player.setControlsSize(); |
4214 control.player.setControlsSize(); |
4207 } |
4215 } |
4568 * control-specific data, to be fed to the imgAreaSelect plugin in |
4576 * control-specific data, to be fed to the imgAreaSelect plugin in |
4569 * wp.media.view.Cropper. |
4577 * wp.media.view.Cropper. |
4570 * |
4578 * |
4571 * @param {wp.media.model.Attachment} attachment |
4579 * @param {wp.media.model.Attachment} attachment |
4572 * @param {wp.media.controller.Cropper} controller |
4580 * @param {wp.media.controller.Cropper} controller |
4573 * @returns {Object} Options |
4581 * @return {Object} Options |
4574 */ |
4582 */ |
4575 calculateImageSelectOptions: function( attachment, controller ) { |
4583 calculateImageSelectOptions: function( attachment, controller ) { |
4576 var control = controller.get( 'control' ), |
4584 var control = controller.get( 'control' ), |
4577 flexWidth = !! parseInt( control.params.flex_width, 10 ), |
4585 flexWidth = !! parseInt( control.params.flex_width, 10 ), |
4578 flexHeight = !! parseInt( control.params.flex_height, 10 ), |
4586 flexHeight = !! parseInt( control.params.flex_height, 10 ), |
4631 }, |
4639 }, |
4632 |
4640 |
4633 /** |
4641 /** |
4634 * Return whether the image must be cropped, based on required dimensions. |
4642 * Return whether the image must be cropped, based on required dimensions. |
4635 * |
4643 * |
4636 * @param {bool} flexW |
4644 * @param {boolean} flexW |
4637 * @param {bool} flexH |
4645 * @param {boolean} flexH |
4638 * @param {int} dstW |
4646 * @param {number} dstW |
4639 * @param {int} dstH |
4647 * @param {number} dstH |
4640 * @param {int} imgW |
4648 * @param {number} imgW |
4641 * @param {int} imgH |
4649 * @param {number} imgH |
4642 * @return {bool} |
4650 * @return {boolean} |
4643 */ |
4651 */ |
4644 mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) { |
4652 mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) { |
4645 if ( true === flexW && true === flexH ) { |
4653 if ( true === flexW && true === flexH ) { |
4646 return false; |
4654 return false; |
4647 } |
4655 } |
4851 * Returns a new instance of api.HeaderTool.ImageModel based on the currently |
4859 * Returns a new instance of api.HeaderTool.ImageModel based on the currently |
4852 * saved header image (if any). |
4860 * saved header image (if any). |
4853 * |
4861 * |
4854 * @since 4.2.0 |
4862 * @since 4.2.0 |
4855 * |
4863 * |
4856 * @returns {Object} Options |
4864 * @return {Object} Options |
4857 */ |
4865 */ |
4858 getInitialHeaderImage: function() { |
4866 getInitialHeaderImage: function() { |
4859 if ( ! api.get().header_image || ! api.get().header_image_data || _.contains( [ 'remove-header', 'random-default-image', 'random-uploaded-image' ], api.get().header_image ) ) { |
4867 if ( ! api.get().header_image || ! api.get().header_image_data || _.contains( [ 'remove-header', 'random-default-image', 'random-uploaded-image' ], api.get().header_image ) ) { |
4860 return new api.HeaderTool.ImageModel(); |
4868 return new api.HeaderTool.ImageModel(); |
4861 } |
4869 } |
4884 * theme-specific data, to be fed to the imgAreaSelect plugin in |
4892 * theme-specific data, to be fed to the imgAreaSelect plugin in |
4885 * wp.media.view.Cropper. |
4893 * wp.media.view.Cropper. |
4886 * |
4894 * |
4887 * @param {wp.media.model.Attachment} attachment |
4895 * @param {wp.media.model.Attachment} attachment |
4888 * @param {wp.media.controller.Cropper} controller |
4896 * @param {wp.media.controller.Cropper} controller |
4889 * @returns {Object} Options |
4897 * @return {Object} Options |
4890 */ |
4898 */ |
4891 calculateImageSelectOptions: function(attachment, controller) { |
4899 calculateImageSelectOptions: function(attachment, controller) { |
4892 var xInit = parseInt(_wpCustomizeHeader.data.width, 10), |
4900 var xInit = parseInt(_wpCustomizeHeader.data.width, 10), |
4893 yInit = parseInt(_wpCustomizeHeader.data.height, 10), |
4901 yInit = parseInt(_wpCustomizeHeader.data.height, 10), |
4894 flexWidth = !! parseInt(_wpCustomizeHeader.data['flex-width'], 10), |
4902 flexWidth = !! parseInt(_wpCustomizeHeader.data['flex-width'], 10), |
5026 /** |
5034 /** |
5027 * Creates a new wp.customize.HeaderTool.ImageModel from provided |
5035 * Creates a new wp.customize.HeaderTool.ImageModel from provided |
5028 * header image data and inserts it into the user-uploaded headers |
5036 * header image data and inserts it into the user-uploaded headers |
5029 * collection. |
5037 * collection. |
5030 * |
5038 * |
5031 * @param {String} url |
5039 * @param {string} url |
5032 * @param {Number} attachmentId |
5040 * @param {number} attachmentId |
5033 * @param {Number} width |
5041 * @param {number} width |
5034 * @param {Number} height |
5042 * @param {number} height |
5035 */ |
5043 */ |
5036 setImageFromURL: function(url, attachmentId, width, height) { |
5044 setImageFromURL: function(url, attachmentId, width, height) { |
5037 var choice, data = {}; |
5045 var choice, data = {}; |
5038 |
5046 |
5039 data.url = url; |
5047 data.url = url; |
5126 // Prevent the modal from showing when the user clicks the action button. |
5134 // Prevent the modal from showing when the user clicks the action button. |
5127 if ( $( event.target ).is( '.theme-actions .button, .update-theme' ) ) { |
5135 if ( $( event.target ).is( '.theme-actions .button, .update-theme' ) ) { |
5128 return; |
5136 return; |
5129 } |
5137 } |
5130 |
5138 |
5131 event.preventDefault(); // Keep this AFTER the key filter above |
5139 event.preventDefault(); // Keep this AFTER the key filter above. |
5132 section = api.section( control.section() ); |
5140 section = api.section( control.section() ); |
5133 section.showDetails( control.params.theme, function() { |
5141 section.showDetails( control.params.theme, function() { |
5134 |
5142 |
5135 // Temporary special function since supplying SFTP credentials does not work yet. See #42184. |
5143 // Temporary special function since supplying SFTP credentials does not work yet. See #42184. |
5136 if ( api.settings.theme._filesystemCredentialsNeeded ) { |
5144 if ( api.settings.theme._filesystemCredentialsNeeded ) { |
5194 if ( 0 !== matchCount ) { |
5202 if ( 0 !== matchCount ) { |
5195 control.activate(); |
5203 control.activate(); |
5196 control.params.priority = 101 - matchCount; // Sort results by match count. |
5204 control.params.priority = 101 - matchCount; // Sort results by match count. |
5197 return true; |
5205 return true; |
5198 } else { |
5206 } else { |
5199 control.deactivate(); // Hide control |
5207 control.deactivate(); // Hide control. |
5200 control.params.priority = 101; |
5208 control.params.priority = 101; |
5201 return false; |
5209 return false; |
5202 } |
5210 } |
5203 }, |
5211 }, |
5204 |
5212 |
5205 /** |
5213 /** |
5206 * Rerender the theme from its JS template with the installed type. |
5214 * Rerender the theme from its JS template with the installed type. |
5207 * |
5215 * |
5208 * @since 4.9.0 |
5216 * @since 4.9.0 |
5209 * |
5217 * |
5210 * @returns {void} |
5218 * @return {void} |
5211 */ |
5219 */ |
5212 rerenderAsInstalled: function( installed ) { |
5220 rerenderAsInstalled: function( installed ) { |
5213 var control = this, section; |
5221 var control = this, section; |
5214 if ( installed ) { |
5222 if ( installed ) { |
5215 control.params.theme.type = 'installed'; |
5223 control.params.theme.type = 'installed'; |
5354 * Make sure editor gets focused when control is focused. |
5362 * Make sure editor gets focused when control is focused. |
5355 * |
5363 * |
5356 * @since 4.9.0 |
5364 * @since 4.9.0 |
5357 * @param {Object} [params] - Focus params. |
5365 * @param {Object} [params] - Focus params. |
5358 * @param {Function} [params.completeCallback] - Function to call when expansion is complete. |
5366 * @param {Function} [params.completeCallback] - Function to call when expansion is complete. |
5359 * @returns {void} |
5367 * @return {void} |
5360 */ |
5368 */ |
5361 focus: function( params ) { |
5369 focus: function( params ) { |
5362 var control = this, extendedParams = _.extend( {}, params ), originalCompleteCallback; |
5370 var control = this, extendedParams = _.extend( {}, params ), originalCompleteCallback; |
5363 originalCompleteCallback = extendedParams.completeCallback; |
5371 originalCompleteCallback = extendedParams.completeCallback; |
5364 extendedParams.completeCallback = function() { |
5372 extendedParams.completeCallback = function() { |
5805 * Convert hour in twelve hour format to twenty four hour format. |
5813 * Convert hour in twelve hour format to twenty four hour format. |
5806 * |
5814 * |
5807 * @since 4.9.0 |
5815 * @since 4.9.0 |
5808 * @param {string} hourInTwelveHourFormat - Hour in twelve hour format. |
5816 * @param {string} hourInTwelveHourFormat - Hour in twelve hour format. |
5809 * @param {string} meridian - Either 'am' or 'pm'. |
5817 * @param {string} meridian - Either 'am' or 'pm'. |
5810 * @returns {string} Hour in twenty four hour format. |
5818 * @return {string} Hour in twenty four hour format. |
5811 */ |
5819 */ |
5812 convertHourToTwentyFourHourFormat: function convertHour( hourInTwelveHourFormat, meridian ) { |
5820 convertHourToTwentyFourHourFormat: function convertHour( hourInTwelveHourFormat, meridian ) { |
5813 var hourInTwentyFourHourFormat, hour, midDayHour = 12; |
5821 var hourInTwentyFourHourFormat, hour, midDayHour = 12; |
5814 |
5822 |
5815 hour = parseInt( hourInTwelveHourFormat, 10 ); |
5823 hour = parseInt( hourInTwelveHourFormat, 10 ); |
6040 * @since 3.4.0 |
6048 * @since 3.4.0 |
6041 * |
6049 * |
6042 * @type {Function} |
6050 * @type {Function} |
6043 * @param {...string} ids - One or more ids for controls to obtain. |
6051 * @param {...string} ids - One or more ids for controls to obtain. |
6044 * @param {deferredControlsCallback} [callback] - Function called when all supplied controls exist. |
6052 * @param {deferredControlsCallback} [callback] - Function called when all supplied controls exist. |
6045 * @returns {wp.customize.Control|undefined|jQuery.promise} Control instance or undefined (if function called with one id param), or promise resolving to requested controls. |
6053 * @return {wp.customize.Control|undefined|jQuery.promise} Control instance or undefined (if function called with one id param), |
|
6054 * or promise resolving to requested controls. |
6046 * |
6055 * |
6047 * @example <caption>Loop over all registered controls.</caption> |
6056 * @example <caption>Loop over all registered controls.</caption> |
6048 * wp.customize.control.each( function( control ) { ... } ); |
6057 * wp.customize.control.each( function( control ) { ... } ); |
6049 * |
6058 * |
6050 * @example <caption>Getting `background_color` control instance.</caption> |
6059 * @example <caption>Getting `background_color` control instance.</caption> |
6101 * @since 3.4.0 |
6110 * @since 3.4.0 |
6102 * |
6111 * |
6103 * @type {Function} |
6112 * @type {Function} |
6104 * @param {...string} ids - One or more ids for sections to obtain. |
6113 * @param {...string} ids - One or more ids for sections to obtain. |
6105 * @param {deferredSectionsCallback} [callback] - Function called when all supplied sections exist. |
6114 * @param {deferredSectionsCallback} [callback] - Function called when all supplied sections exist. |
6106 * @returns {wp.customize.Section|undefined|jQuery.promise} Section instance or undefined (if function called with one id param), or promise resolving to requested sections. |
6115 * @return {wp.customize.Section|undefined|jQuery.promise} Section instance or undefined (if function called with one id param), |
|
6116 * or promise resolving to requested sections. |
6107 * |
6117 * |
6108 * @example <caption>Loop over all registered sections.</caption> |
6118 * @example <caption>Loop over all registered sections.</caption> |
6109 * wp.customize.section.each( function( section ) { ... } ) |
6119 * wp.customize.section.each( function( section ) { ... } ) |
6110 * |
6120 * |
6111 * @example <caption>Getting `title_tagline` section instance.</caption> |
6121 * @example <caption>Getting `title_tagline` section instance.</caption> |
6135 * @since 4.0.0 |
6145 * @since 4.0.0 |
6136 * |
6146 * |
6137 * @type {Function} |
6147 * @type {Function} |
6138 * @param {...string} ids - One or more ids for panels to obtain. |
6148 * @param {...string} ids - One or more ids for panels to obtain. |
6139 * @param {deferredPanelsCallback} [callback] - Function called when all supplied panels exist. |
6149 * @param {deferredPanelsCallback} [callback] - Function called when all supplied panels exist. |
6140 * @returns {wp.customize.Panel|undefined|jQuery.promise} Panel instance or undefined (if function called with one id param), or promise resolving to requested panels. |
6150 * @return {wp.customize.Panel|undefined|jQuery.promise} Panel instance or undefined (if function called with one id param), |
|
6151 * or promise resolving to requested panels. |
6141 * |
6152 * |
6142 * @example <caption>Loop over all registered panels.</caption> |
6153 * @example <caption>Loop over all registered panels.</caption> |
6143 * wp.customize.panel.each( function( panel ) { ... } ) |
6154 * wp.customize.panel.each( function( panel ) { ... } ) |
6144 * |
6155 * |
6145 * @example <caption>Getting nav_menus panel instance.</caption> |
6156 * @example <caption>Getting nav_menus panel instance.</caption> |
6169 * @since 4.9.0 |
6180 * @since 4.9.0 |
6170 * |
6181 * |
6171 * @type {Function} |
6182 * @type {Function} |
6172 * @param {...string} codes - One or more codes for notifications to obtain. |
6183 * @param {...string} codes - One or more codes for notifications to obtain. |
6173 * @param {deferredNotificationsCallback} [callback] - Function called when all supplied notifications exist. |
6184 * @param {deferredNotificationsCallback} [callback] - Function called when all supplied notifications exist. |
6174 * @returns {wp.customize.Notification|undefined|jQuery.promise} notification instance or undefined (if function called with one code param), or promise resolving to requested notifications. |
6185 * @return {wp.customize.Notification|undefined|jQuery.promise} Notification instance or undefined (if function called with one code param), |
|
6186 * or promise resolving to requested notifications. |
6175 * |
6187 * |
6176 * @example <caption>Check if existing notification</caption> |
6188 * @example <caption>Check if existing notification</caption> |
6177 * exists = wp.customize.notifications.has( 'a_new_day_arrived' ); |
6189 * exists = wp.customize.notifications.has( 'a_new_day_arrived' ); |
6178 * |
6190 * |
6179 * @example <caption>Obtain existing notification</caption> |
6191 * @example <caption>Obtain existing notification</caption> |
6204 * allows for seamless replacement of an existing preview. |
6216 * allows for seamless replacement of an existing preview. |
6205 * |
6217 * |
6206 * @constructs wp.customize.PreviewFrame |
6218 * @constructs wp.customize.PreviewFrame |
6207 * @augments wp.customize.Messenger |
6219 * @augments wp.customize.Messenger |
6208 * |
6220 * |
6209 * @param {object} params.container |
6221 * @param {Object} params.container |
6210 * @param {object} params.previewUrl |
6222 * @param {Object} params.previewUrl |
6211 * @param {object} params.query |
6223 * @param {Object} params.query |
6212 * @param {object} options |
6224 * @param {Object} options |
6213 */ |
6225 */ |
6214 initialize: function( params, options ) { |
6226 initialize: function( params, options ) { |
6215 var deferred = $.Deferred(); |
6227 var deferred = $.Deferred(); |
6216 |
6228 |
6217 /* |
6229 /* |
6442 |
6454 |
6443 /** |
6455 /** |
6444 * @constructs wp.customize.Previewer |
6456 * @constructs wp.customize.Previewer |
6445 * @augments wp.customize.Messenger |
6457 * @augments wp.customize.Messenger |
6446 * |
6458 * |
6447 * @param {array} params.allowedUrls |
6459 * @param {Array} params.allowedUrls |
6448 * @param {string} params.container A selector or jQuery element for the preview |
6460 * @param {string} params.container A selector or jQuery element for the preview |
6449 * frame to be placed. |
6461 * frame to be placed. |
6450 * @param {string} params.form |
6462 * @param {string} params.form |
6451 * @param {string} params.previewUrl The URL to preview. |
6463 * @param {string} params.previewUrl The URL to preview. |
6452 * @param {object} options |
6464 * @param {Object} options |
6453 */ |
6465 */ |
6454 initialize: function( params, options ) { |
6466 initialize: function( params, options ) { |
6455 var previewer = this, |
6467 var previewer = this, |
6456 urlParser = document.createElement( 'a' ); |
6468 urlParser = document.createElement( 'a' ); |
6457 |
6469 |
6492 api.Messenger.prototype.initialize.call( previewer, params ); |
6504 api.Messenger.prototype.initialize.call( previewer, params ); |
6493 |
6505 |
6494 urlParser.href = previewer.origin(); |
6506 urlParser.href = previewer.origin(); |
6495 previewer.add( 'scheme', urlParser.protocol.replace( /:$/, '' ) ); |
6507 previewer.add( 'scheme', urlParser.protocol.replace( /:$/, '' ) ); |
6496 |
6508 |
6497 // Limit the URL to internal, front-end links. |
6509 /* |
6498 // |
6510 * Limit the URL to internal, front-end links. |
6499 // If the front end and the admin are served from the same domain, load the |
6511 * |
6500 // preview over ssl if the Customizer is being loaded over ssl. This avoids |
6512 * If the front end and the admin are served from the same domain, load the |
6501 // insecure content warnings. This is not attempted if the admin and front end |
6513 * preview over ssl if the Customizer is being loaded over ssl. This avoids |
6502 // are on different domains to avoid the case where the front end doesn't have |
6514 * insecure content warnings. This is not attempted if the admin and front end |
6503 // ssl certs. |
6515 * are on different domains to avoid the case where the front end doesn't have |
|
6516 * ssl certs. |
|
6517 */ |
6504 |
6518 |
6505 previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) { |
6519 previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) { |
6506 var result = null, urlParser, queryParams, parsedAllowedUrl, parsedCandidateUrls = []; |
6520 var result = null, urlParser, queryParams, parsedAllowedUrl, parsedCandidateUrls = []; |
6507 urlParser = document.createElement( 'a' ); |
6521 urlParser = document.createElement( 'a' ); |
6508 urlParser.href = to; |
6522 urlParser.href = to; |
6593 * Handle the preview receiving the ready message. |
6607 * Handle the preview receiving the ready message. |
6594 * |
6608 * |
6595 * @since 4.7.0 |
6609 * @since 4.7.0 |
6596 * @access public |
6610 * @access public |
6597 * |
6611 * |
6598 * @param {object} data - Data from preview. |
6612 * @param {Object} data - Data from preview. |
6599 * @param {string} data.currentUrl - Current URL. |
6613 * @param {string} data.currentUrl - Current URL. |
6600 * @param {object} data.activePanels - Active panels. |
6614 * @param {Object} data.activePanels - Active panels. |
6601 * @param {object} data.activeSections Active sections. |
6615 * @param {Object} data.activeSections Active sections. |
6602 * @param {object} data.activeControls Active controls. |
6616 * @param {Object} data.activeControls Active controls. |
6603 * @returns {void} |
6617 * @return {void} |
6604 */ |
6618 */ |
6605 ready: function( data ) { |
6619 ready: function( data ) { |
6606 var previewer = this, synced = {}, constructs; |
6620 var previewer = this, synced = {}, constructs; |
6607 |
6621 |
6608 synced.settings = api.get(); |
6622 synced.settings = api.get(); |
6900 * @alias wp.customize._handleSettingValidities |
6915 * @alias wp.customize._handleSettingValidities |
6901 * |
6916 * |
6902 * @since 4.6.0 |
6917 * @since 4.6.0 |
6903 * @private |
6918 * @private |
6904 * |
6919 * |
6905 * @param {object} args |
6920 * @param {Object} args |
6906 * @param {object} args.settingValidities |
6921 * @param {Object} args.settingValidities |
6907 * @param {boolean} [args.focusInvalidControl=false] |
6922 * @param {boolean} [args.focusInvalidControl=false] |
6908 * @returns {void} |
6923 * @return {void} |
6909 */ |
6924 */ |
6910 api._handleSettingValidities = function handleSettingValidities( args ) { |
6925 api._handleSettingValidities = function handleSettingValidities( args ) { |
6911 var invalidSettingControls, invalidSettings = [], wasFocused = false; |
6926 var invalidSettingControls, invalidSettings = [], wasFocused = false; |
6912 |
6927 |
6913 // Find the controls that correspond to each invalid setting. |
6928 // Find the controls that correspond to each invalid setting. |
6976 * |
6991 * |
6977 * @alias wp.customize.findControlsForSettings |
6992 * @alias wp.customize.findControlsForSettings |
6978 * |
6993 * |
6979 * @since 4.6.0 |
6994 * @since 4.6.0 |
6980 * @param {string[]} settingIds Setting IDs. |
6995 * @param {string[]} settingIds Setting IDs. |
6981 * @returns {object<string, wp.customize.Control>} Mapping setting ids to arrays of controls. |
6996 * @return {Object<string, wp.customize.Control>} Mapping setting ids to arrays of controls. |
6982 */ |
6997 */ |
6983 api.findControlsForSettings = function findControlsForSettings( settingIds ) { |
6998 api.findControlsForSettings = function findControlsForSettings( settingIds ) { |
6984 var controls = {}, settingControls; |
6999 var controls = {}, settingControls; |
6985 _.each( _.unique( settingIds ), function( settingId ) { |
7000 _.each( _.unique( settingIds ), function( settingId ) { |
6986 var setting = api( settingId ); |
7001 var setting = api( settingId ); |
7041 } ); |
7056 } ); |
7042 wasReflowed = true; |
7057 wasReflowed = true; |
7043 } |
7058 } |
7044 } ); |
7059 } ); |
7045 |
7060 |
7046 // Sort the root panels and sections |
7061 // Sort the root panels and sections. |
7047 rootNodes.sort( api.utils.prioritySort ); |
7062 rootNodes.sort( api.utils.prioritySort ); |
7048 rootHeadContainers = _.pluck( rootNodes, 'headContainer' ); |
7063 rootHeadContainers = _.pluck( rootNodes, 'headContainer' ); |
7049 appendContainer = $( '#customize-theme-controls .customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable |
7064 appendContainer = $( '#customize-theme-controls .customize-pane-parent' ); // @todo This should be defined elsewhere, and to be configurable. |
7050 if ( ! api.utils.areElementListsEqual( rootHeadContainers, appendContainer.children() ) ) { |
7065 if ( ! api.utils.areElementListsEqual( rootHeadContainers, appendContainer.children() ) ) { |
7051 _( rootNodes ).each( function ( rootNode ) { |
7066 _( rootNodes ).each( function ( rootNode ) { |
7052 appendContainer.append( rootNode.headContainer ); |
7067 appendContainer.append( rootNode.headContainer ); |
7053 } ); |
7068 } ); |
7054 wasReflowed = true; |
7069 wasReflowed = true; |
7055 } |
7070 } |
7056 |
7071 |
7057 // Now re-trigger the active Value callbacks to that the panels and sections can decide whether they can be rendered |
7072 // Now re-trigger the active Value callbacks so that the panels and sections can decide whether they can be rendered. |
7058 api.panel.each( function ( panel ) { |
7073 api.panel.each( function ( panel ) { |
7059 var value = panel.active(); |
7074 var value = panel.active(); |
7060 panel.active.callbacks.fireWith( panel.active, [ value, value ] ); |
7075 panel.active.callbacks.fireWith( panel.active, [ value, value ] ); |
7061 } ); |
7076 } ); |
7062 api.section.each( function ( section ) { |
7077 api.section.each( function ( section ) { |
7063 var value = section.active(); |
7078 var value = section.active(); |
7064 section.active.callbacks.fireWith( section.active, [ value, value ] ); |
7079 section.active.callbacks.fireWith( section.active, [ value, value ] ); |
7065 } ); |
7080 } ); |
7066 |
7081 |
7067 // Restore focus if there was a reflow and there was an active (focused) element |
7082 // Restore focus if there was a reflow and there was an active (focused) element. |
7068 if ( wasReflowed && activeElement ) { |
7083 if ( wasReflowed && activeElement ) { |
7069 activeElement.focus(); |
7084 activeElement.focus(); |
7070 } |
7085 } |
7071 api.trigger( 'pane-contents-reflowed' ); |
7086 api.trigger( 'pane-contents-reflowed' ); |
7072 }, api ); |
7087 }, api ); |
7202 function highlightScheduleButton() { |
7217 function highlightScheduleButton() { |
7203 if ( ! cancelScheduleButtonReminder ) { |
7218 if ( ! cancelScheduleButtonReminder ) { |
7204 cancelScheduleButtonReminder = api.utils.highlightButton( btnWrapper, { |
7219 cancelScheduleButtonReminder = api.utils.highlightButton( btnWrapper, { |
7205 delay: 1000, |
7220 delay: 1000, |
7206 |
7221 |
7207 // Only abort the reminder when the save button is focused. |
7222 /* |
7208 // If the user clicks the settings button to toggle the |
7223 * Only abort the reminder when the save button is focused. |
7209 // settings closed, we'll still remind them. |
7224 * If the user clicks the settings button to toggle the |
|
7225 * settings closed, we'll still remind them. |
|
7226 */ |
7210 focusTarget: saveBtn |
7227 focusTarget: saveBtn |
7211 } ); |
7228 } ); |
7212 } |
7229 } |
7213 } |
7230 } |
7214 function cancelHighlightScheduleButton() { |
7231 function cancelHighlightScheduleButton() { |
7420 * has been added to the post type. |
7437 * has been added to the post type. |
7421 * |
7438 * |
7422 * @since 3.4.0 |
7439 * @since 3.4.0 |
7423 * @since 4.7.0 Added args param and return value. |
7440 * @since 4.7.0 Added args param and return value. |
7424 * |
7441 * |
7425 * @param {object} [args] Args. |
7442 * @param {Object} [args] Args. |
7426 * @param {string} [args.status=publish] Status. |
7443 * @param {string} [args.status=publish] Status. |
7427 * @param {string} [args.date] Date, in local time in MySQL format. |
7444 * @param {string} [args.date] Date, in local time in MySQL format. |
7428 * @param {string} [args.title] Title |
7445 * @param {string} [args.title] Title |
7429 * @returns {jQuery.promise} Promise. |
7446 * @return {jQuery.promise} Promise. |
7430 */ |
7447 */ |
7431 save: function( args ) { |
7448 save: function( args ) { |
7432 var previewer = this, |
7449 var previewer = this, |
7433 deferred = $.Deferred(), |
7450 deferred = $.Deferred(), |
7434 changesetStatus = api.state( 'selectedChangesetStatus' ).get(), |
7451 changesetStatus = api.state( 'selectedChangesetStatus' ).get(), |
7806 $.extend( api.settings.nonce, nonce ); |
7823 $.extend( api.settings.nonce, nonce ); |
7807 $.extend( api.previewer.nonce, nonce ); |
7824 $.extend( api.previewer.nonce, nonce ); |
7808 api.previewer.send( 'nonce-refresh', nonce ); |
7825 api.previewer.send( 'nonce-refresh', nonce ); |
7809 }); |
7826 }); |
7810 |
7827 |
7811 // Create Settings |
7828 // Create Settings. |
7812 $.each( api.settings.settings, function( id, data ) { |
7829 $.each( api.settings.settings, function( id, data ) { |
7813 var Constructor = api.settingConstructor[ data.type ] || api.Setting; |
7830 var Constructor = api.settingConstructor[ data.type ] || api.Setting; |
7814 api.add( new Constructor( id, data.value, { |
7831 api.add( new Constructor( id, data.value, { |
7815 transport: data.transport, |
7832 transport: data.transport, |
7816 previewer: api.previewer, |
7833 previewer: api.previewer, |
7817 dirty: !! data.dirty |
7834 dirty: !! data.dirty |
7818 } ) ); |
7835 } ) ); |
7819 }); |
7836 }); |
7820 |
7837 |
7821 // Create Panels |
7838 // Create Panels. |
7822 $.each( api.settings.panels, function ( id, data ) { |
7839 $.each( api.settings.panels, function ( id, data ) { |
7823 var Constructor = api.panelConstructor[ data.type ] || api.Panel, options; |
7840 var Constructor = api.panelConstructor[ data.type ] || api.Panel, options; |
7824 options = _.extend( { params: data }, data ); // Inclusion of params alias is for back-compat for custom panels that expect to augment this property. |
7841 // Inclusion of params alias is for back-compat for custom panels that expect to augment this property. |
|
7842 options = _.extend( { params: data }, data ); |
7825 api.panel.add( new Constructor( id, options ) ); |
7843 api.panel.add( new Constructor( id, options ) ); |
7826 }); |
7844 }); |
7827 |
7845 |
7828 // Create Sections |
7846 // Create Sections. |
7829 $.each( api.settings.sections, function ( id, data ) { |
7847 $.each( api.settings.sections, function ( id, data ) { |
7830 var Constructor = api.sectionConstructor[ data.type ] || api.Section, options; |
7848 var Constructor = api.sectionConstructor[ data.type ] || api.Section, options; |
7831 options = _.extend( { params: data }, data ); // Inclusion of params alias is for back-compat for custom sections that expect to augment this property. |
7849 // Inclusion of params alias is for back-compat for custom sections that expect to augment this property. |
|
7850 options = _.extend( { params: data }, data ); |
7832 api.section.add( new Constructor( id, options ) ); |
7851 api.section.add( new Constructor( id, options ) ); |
7833 }); |
7852 }); |
7834 |
7853 |
7835 // Create Controls |
7854 // Create Controls. |
7836 $.each( api.settings.controls, function( id, data ) { |
7855 $.each( api.settings.controls, function( id, data ) { |
7837 var Constructor = api.controlConstructor[ data.type ] || api.Control, options; |
7856 var Constructor = api.controlConstructor[ data.type ] || api.Control, options; |
7838 options = _.extend( { params: data }, data ); // Inclusion of params alias is for back-compat for custom controls that expect to augment this property. |
7857 // Inclusion of params alias is for back-compat for custom controls that expect to augment this property. |
|
7858 options = _.extend( { params: data }, data ); |
7839 api.control.add( new Constructor( id, options ) ); |
7859 api.control.add( new Constructor( id, options ) ); |
7840 }); |
7860 }); |
7841 |
7861 |
7842 // Focus the autofocused element |
7862 // Focus the autofocused element. |
7843 _.each( [ 'panel', 'section', 'control' ], function( type ) { |
7863 _.each( [ 'panel', 'section', 'control' ], function( type ) { |
7844 var id = api.settings.autofocus[ type ]; |
7864 var id = api.settings.autofocus[ type ]; |
7845 if ( ! id ) { |
7865 if ( ! id ) { |
7846 return; |
7866 return; |
7847 } |
7867 } |
7890 }); |
7910 }); |
7891 |
7911 |
7892 api.notifications.render(); |
7912 api.notifications.render(); |
7893 }); |
7913 }); |
7894 |
7914 |
7895 // Save and activated states |
7915 // Save and activated states. |
7896 (function( state ) { |
7916 (function( state ) { |
7897 var saved = state.instance( 'saved' ), |
7917 var saved = state.instance( 'saved' ), |
7898 saving = state.instance( 'saving' ), |
7918 saving = state.instance( 'saving' ), |
7899 trashing = state.instance( 'trashing' ), |
7919 trashing = state.instance( 'trashing' ), |
7900 activated = state.instance( 'activated' ), |
7920 activated = state.instance( 'activated' ), |
8099 * @augments wp.customize.OverlayNotification |
8119 * @augments wp.customize.OverlayNotification |
8100 * |
8120 * |
8101 * @since 4.9.0 |
8121 * @since 4.9.0 |
8102 * |
8122 * |
8103 * @param {string} [code] - Code. |
8123 * @param {string} [code] - Code. |
8104 * @param {object} [params] - Params. |
8124 * @param {Object} [params] - Params. |
8105 */ |
8125 */ |
8106 initialize: function( code, params ) { |
8126 initialize: function( code, params ) { |
8107 var notification = this, _code, _params; |
8127 var notification = this, _code, _params; |
8108 _code = code || 'changeset_locked'; |
8128 _code = code || 'changeset_locked'; |
8109 _params = _.extend( |
8129 _params = _.extend( |
8110 { |
8130 { |
|
8131 message: '', |
8111 type: 'warning', |
8132 type: 'warning', |
8112 containerClasses: '', |
8133 containerClasses: '', |
8113 lockUser: {} |
8134 lockUser: {} |
8114 }, |
8135 }, |
8115 params |
8136 params |
8614 * Reposition header on throttled `scroll` event. |
8635 * Reposition header on throttled `scroll` event. |
8615 * |
8636 * |
8616 * @since 4.7.0 |
8637 * @since 4.7.0 |
8617 * @access private |
8638 * @access private |
8618 * |
8639 * |
8619 * @param {object} header - Header. |
8640 * @param {Object} header - Header. |
8620 * @param {number} scrollTop - Scroll top. |
8641 * @param {number} scrollTop - Scroll top. |
8621 * @param {number} scrollDirection - Scroll direction, negative number being up and positive being down. |
8642 * @param {number} scrollDirection - Scroll direction, negative number being up and positive being down. |
8622 * @returns {void} |
8643 * @return {void} |
8623 */ |
8644 */ |
8624 positionStickyHeader = function( header, scrollTop, scrollDirection ) { |
8645 positionStickyHeader = function( header, scrollTop, scrollDirection ) { |
8625 var headerElement = header.element, |
8646 var headerElement = header.element, |
8626 headerParent = header.parent, |
8647 headerParent = header.parent, |
8627 headerHeight = header.height, |
8648 headerHeight = header.height, |
8684 headerParent.css( 'padding-top', headerHeight + 'px' ); |
8705 headerParent.css( 'padding-top', headerHeight + 'px' ); |
8685 } |
8706 } |
8686 }; |
8707 }; |
8687 }()); |
8708 }()); |
8688 |
8709 |
8689 // Previewed device bindings. (The api.previewedDevice property is how this Value was first introduced, but since it has moved to api.state.) |
8710 // Previewed device bindings. (The api.previewedDevice property |
|
8711 // is how this Value was first introduced, but since it has moved to api.state.) |
8690 api.previewedDevice = api.state( 'previewedDevice' ); |
8712 api.previewedDevice = api.state( 'previewedDevice' ); |
8691 |
8713 |
8692 // Set the default device. |
8714 // Set the default device. |
8693 api.bind( 'ready', function() { |
8715 api.bind( 'ready', function() { |
8694 _.find( api.settings.previewableDevices, function( value, key ) { |
8716 _.find( api.settings.previewableDevices, function( value, key ) { |
8791 function startPromptingBeforeUnload() { |
8813 function startPromptingBeforeUnload() { |
8792 api.unbind( 'change', startPromptingBeforeUnload ); |
8814 api.unbind( 'change', startPromptingBeforeUnload ); |
8793 api.state( 'selectedChangesetStatus' ).unbind( startPromptingBeforeUnload ); |
8815 api.state( 'selectedChangesetStatus' ).unbind( startPromptingBeforeUnload ); |
8794 api.state( 'selectedChangesetDate' ).unbind( startPromptingBeforeUnload ); |
8816 api.state( 'selectedChangesetDate' ).unbind( startPromptingBeforeUnload ); |
8795 |
8817 |
8796 // Prompt user with AYS dialog if leaving the Customizer with unsaved changes |
8818 // Prompt user with AYS dialog if leaving the Customizer with unsaved changes. |
8797 $( window ).on( 'beforeunload.customize-confirm', function() { |
8819 $( window ).on( 'beforeunload.customize-confirm', function() { |
8798 if ( ! isCleanState() && ! api.state( 'changesetLocked' ).get() ) { |
8820 if ( ! isCleanState() && ! api.state( 'changesetLocked' ).get() ) { |
8799 setTimeout( function() { |
8821 setTimeout( function() { |
8800 overlay.removeClass( 'customize-loading' ); |
8822 overlay.removeClass( 'customize-loading' ); |
8801 }, 1 ); |
8823 }, 1 ); |
8888 } |
8910 } |
8889 |
8911 |
8890 // Initialize the connection with the parent frame. |
8912 // Initialize the connection with the parent frame. |
8891 parent.send( 'ready' ); |
8913 parent.send( 'ready' ); |
8892 |
8914 |
8893 // Control visibility for default controls |
8915 // Control visibility for default controls. |
8894 $.each({ |
8916 $.each({ |
8895 'background_image': { |
8917 'background_image': { |
8896 controls: [ 'background_preset', 'background_position', 'background_size', 'background_repeat', 'background_attachment' ], |
8918 controls: [ 'background_preset', 'background_position', 'background_size', 'background_repeat', 'background_attachment' ], |
8897 callback: function( to ) { return !! to; } |
8919 callback: function( to ) { return !! to; } |
8898 }, |
8920 }, |
8920 }); |
8942 }); |
8921 |
8943 |
8922 api.control( 'background_preset', function( control ) { |
8944 api.control( 'background_preset', function( control ) { |
8923 var visibility, defaultValues, values, toggleVisibility, updateSettings, preset; |
8945 var visibility, defaultValues, values, toggleVisibility, updateSettings, preset; |
8924 |
8946 |
8925 visibility = { // position, size, repeat, attachment |
8947 visibility = { // position, size, repeat, attachment. |
8926 'default': [ false, false, false, false ], |
8948 'default': [ false, false, false, false ], |
8927 'fill': [ true, false, false, false ], |
8949 'fill': [ true, false, false, false ], |
8928 'fit': [ true, false, true, false ], |
8950 'fit': [ true, false, true, false ], |
8929 'repeat': [ true, false, false, true ], |
8951 'repeat': [ true, false, false, true ], |
8930 'custom': [ true, true, true, true ] |
8952 'custom': [ true, true, true, true ] |
8936 _wpCustomizeBackground.defaults['default-size'], |
8958 _wpCustomizeBackground.defaults['default-size'], |
8937 _wpCustomizeBackground.defaults['default-repeat'], |
8959 _wpCustomizeBackground.defaults['default-repeat'], |
8938 _wpCustomizeBackground.defaults['default-attachment'] |
8960 _wpCustomizeBackground.defaults['default-attachment'] |
8939 ]; |
8961 ]; |
8940 |
8962 |
8941 values = { // position_x, position_y, size, repeat, attachment |
8963 values = { // position_x, position_y, size, repeat, attachment. |
8942 'default': defaultValues, |
8964 'default': defaultValues, |
8943 'fill': [ 'left', 'top', 'cover', 'no-repeat', 'fixed' ], |
8965 'fill': [ 'left', 'top', 'cover', 'no-repeat', 'fixed' ], |
8944 'fit': [ 'left', 'top', 'contain', 'no-repeat', 'fixed' ], |
8966 'fit': [ 'left', 'top', 'contain', 'no-repeat', 'fixed' ], |
8945 'repeat': [ 'left', 'top', 'auto', 'repeat', 'scroll' ] |
8967 'repeat': [ 'left', 'top', 'auto', 'repeat', 'scroll' ] |
8946 }; |
8968 }; |
8947 |
8969 |
8948 // @todo These should actually toggle the active state, but without the preview overriding the state in data.activeControls. |
8970 // @todo These should actually toggle the active state, |
|
8971 // but without the preview overriding the state in data.activeControls. |
8949 toggleVisibility = function( preset ) { |
8972 toggleVisibility = function( preset ) { |
8950 _.each( [ 'background_position', 'background_size', 'background_repeat', 'background_attachment' ], function( controlId, i ) { |
8973 _.each( [ 'background_position', 'background_size', 'background_repeat', 'background_attachment' ], function( controlId, i ) { |
8951 var control = api.control( controlId ); |
8974 var control = api.control( controlId ); |
8952 if ( control ) { |
8975 if ( control ) { |
8953 control.container.toggle( visibility[ preset ][ i ] ); |
8976 control.container.toggle( visibility[ preset ][ i ] ); |