Changeset 41374
- Timestamp:
- 09/12/2017 07:02:49 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/css/customize-controls.css
r41368 r41374 767 767 margin: 4px 0 8px 0; 768 768 padding: 0; 769 display: none;770 769 cursor: default; 771 770 } … … 797 796 .customize-control-text.has-error input { 798 797 outline: 2px solid #dc3232; 798 } 799 800 #customize-controls #customize-notifications-area { 801 position: absolute; 802 top: 46px; 803 width: 100%; 804 max-height: 210px; 805 overflow-x: hidden; 806 overflow-y: auto; 807 border-bottom: 1px solid #ddd; 808 display: block; 809 padding: 0; 810 margin: 0; 811 } 812 813 #customize-controls #customize-notifications-area > ul, 814 #customize-controls #customize-notifications-area .notice { 815 margin: 0; 816 } 817 #customize-controls #customize-notifications-area .notice { 818 padding: 9px 14px; 819 } 820 #customize-controls #customize-notifications-area .notice.is-dismissible { 821 padding-right: 38px; 822 } 823 #customize-controls #customize-notifications-area .notice + .notice { 824 margin-top: 1px; 799 825 } 800 826 -
trunk/src/wp-admin/customize.php
r40704 r41374 152 152 153 153 <div id="widgets-right" class="wp-clearfix"><!-- For Widget Customizer, many widgets try to look for instances under div#widgets-right, so we have to add that ID to a container div in the Customizer for compat --> 154 <div class="wp-full-overlay-sidebar-content" tabindex="-1"> 155 <div id="customize-info" class="accordion-section customize-info"> 156 <div class="accordion-section-title"> 157 <span class="preview-notice"><?php 158 echo sprintf( __( 'You are customizing %s' ), '<strong class="panel-title site-title">' . get_bloginfo( 'name', 'display' ) . '</strong>' ); 159 ?></span> 160 <button type="button" class="customize-help-toggle dashicons dashicons-editor-help" aria-expanded="false"><span class="screen-reader-text"><?php _e( 'Help' ); ?></span></button> 154 <div id="customize-notifications-area" class="customize-control-notifications-container"> 155 <ul></ul> 156 </div> 157 <div class="wp-full-overlay-sidebar-content" tabindex="-1"> 158 <div id="customize-info" class="accordion-section customize-info"> 159 <div class="accordion-section-title"> 160 <span class="preview-notice"><?php 161 echo sprintf( __( 'You are customizing %s' ), '<strong class="panel-title site-title">' . get_bloginfo( 'name', 'display' ) . '</strong>' ); 162 ?></span> 163 <button type="button" class="customize-help-toggle dashicons dashicons-editor-help" aria-expanded="false"><span class="screen-reader-text"><?php _e( 'Help' ); ?></span></button> 164 </div> 165 <div class="customize-panel-description"><?php 166 _e( 'The Customizer allows you to preview changes to your site before publishing them. You can navigate to different pages on your site within the preview. Edit shortcuts are shown for some editable elements.' ); 167 ?></div> 161 168 </div> 162 <div class="customize-panel-description"><?php 163 _e( 'The Customizer allows you to preview changes to your site before publishing them. You can navigate to different pages on your site within the preview. Edit shortcuts are shown for some editable elements.' ); 164 ?></div> 169 170 <div id="customize-theme-controls"> 171 <ul class="customize-pane-parent"><?php // Panels and sections are managed here via JavaScript ?></ul> 172 </div> 165 173 </div> 166 167 <div id="customize-theme-controls">168 <ul class="customize-pane-parent"><?php // Panels and sections are managed here via JavaScript ?></ul>169 </div>170 </div>171 174 </div> 172 175 -
trunk/src/wp-admin/js/customize-controls.js
r41368 r41374 1 /* global _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer */1 /* global _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer, console */ 2 2 (function( exports, $ ){ 3 3 var Container, focus, normalizedTransitionendEventName, api = wp.customize; 4 5 /** 6 * A collection of observable notifications. 7 * 8 * @since 4.9.0 9 * @class 10 * @augments wp.customize.Values 11 */ 12 api.Notifications = api.Values.extend({ 13 14 /** 15 * Whether the alternative style should be used. 16 * 17 * @since 4.9.0 18 * @type {boolean} 19 */ 20 alt: false, 21 22 /** 23 * The default constructor for items of the collection. 24 * 25 * @since 4.9.0 26 * @type {object} 27 */ 28 defaultConstructor: api.Notification, 29 30 /** 31 * Initialize notifications area. 32 * 33 * @since 4.9.0 34 * @constructor 35 * @param {object} options - Options. 36 * @param {jQuery} [options.container] - Container element for notifications. This can be injected later. 37 * @param {boolean} [options.alt] - Whether alternative style should be used when rendering notifications. 38 * @returns {void} 39 * @this {wp.customize.Notifications} 40 */ 41 initialize: function( options ) { 42 var collection = this; 43 44 api.Values.prototype.initialize.call( collection, options ); 45 46 // Keep track of the order in which the notifications were added for sorting purposes. 47 collection._addedIncrement = 0; 48 collection._addedOrder = {}; 49 50 // Trigger change event when notification is added or removed. 51 collection.bind( 'add', function( notification ) { 52 collection.trigger( 'change', notification ); 53 }); 54 collection.bind( 'removed', function( notification ) { 55 collection.trigger( 'change', notification ); 56 }); 57 }, 58 59 /** 60 * Get the number of notifications added. 61 * 62 * @since 4.9.0 63 * @return {number} Count of notifications. 64 */ 65 count: function() { 66 return _.size( this._value ); 67 }, 68 69 /** 70 * Add notification to the collection. 71 * 72 * @since 4.9.0 73 * @param {string} code - Notification code. 74 * @param {object} params - Notification params. 75 * @return {api.Notification} Added instance (or existing instance if it was already added). 76 */ 77 add: function( code, params ) { 78 var collection = this; 79 if ( ! collection.has( code ) ) { 80 collection._addedIncrement += 1; 81 collection._addedOrder[ code ] = collection._addedIncrement; 82 } 83 return api.Values.prototype.add.call( this, code, params ); 84 }, 85 86 /** 87 * Add notification to the collection. 88 * 89 * @since 4.9.0 90 * @param {string} code - Notification code to remove. 91 * @return {api.Notification} Added instance (or existing instance if it was already added). 92 */ 93 remove: function( code ) { 94 var collection = this; 95 delete collection._addedOrder[ code ]; 96 return api.Values.prototype.remove.call( this, code ); 97 }, 98 99 /** 100 * Get list of notifications. 101 * 102 * Notifications may be sorted by type followed by added time. 103 * 104 * @since 4.9.0 105 * @param {object} args - Args. 106 * @param {boolean} [args.sort=false] - Whether to return the notifications sorted. 107 * @return {Array.<wp.customize.Notification>} Notifications. 108 * @this {wp.customize.Notifications} 109 */ 110 get: function( args ) { 111 var collection = this, notifications, errorTypePriorities, params; 112 notifications = _.values( collection._value ); 113 114 params = _.extend( 115 { sort: false }, 116 args 117 ); 118 119 if ( params.sort ) { 120 errorTypePriorities = { error: 4, warning: 3, success: 2, info: 1 }; 121 notifications.sort( function( a, b ) { 122 var aPriority = 0, bPriority = 0; 123 if ( ! _.isUndefined( errorTypePriorities[ a.type ] ) ) { 124 aPriority = errorTypePriorities[ a.type ]; 125 } 126 if ( ! _.isUndefined( errorTypePriorities[ b.type ] ) ) { 127 bPriority = errorTypePriorities[ b.type ]; 128 } 129 if ( aPriority !== bPriority ) { 130 return bPriority - aPriority; // Show errors first. 131 } 132 return collection._addedOrder[ b.code ] - collection._addedOrder[ a.code ]; // Show newer notifications higher. 133 }); 134 } 135 136 return notifications; 137 }, 138 139 /** 140 * Render notifications area. 141 * 142 * @since 4.9.0 143 * @returns {void} 144 * @this {wp.customize.Notifications} 145 */ 146 render: function() { 147 var collection = this, 148 notifications, 149 renderedNotificationContainers, 150 prevRenderedCodes, 151 nextRenderedCodes, 152 addedCodes, 153 removedCodes, 154 listElement; 155 156 // Short-circuit if there are no container to render into. 157 if ( ! collection.container || ! collection.container.length ) { 158 return; 159 } 160 listElement = collection.container.children( 'ul' ).first(); 161 if ( ! listElement.length ) { 162 listElement = $( '<ul></ul>' ); 163 collection.container.append( listElement ); 164 } 165 166 notifications = collection.get( { sort: true } ); 167 168 renderedNotificationContainers = {}; 169 listElement.find( '> [data-code]' ).each( function() { 170 renderedNotificationContainers[ $( this ).data( 'code' ) ] = $( this ); 171 }); 172 173 collection.container.toggle( 0 !== notifications.length ); 174 175 nextRenderedCodes = _.pluck( notifications, 'code' ); 176 prevRenderedCodes = _.keys( renderedNotificationContainers ); 177 178 // Short-circuit if there are no notifications added. 179 if ( _.isEqual( nextRenderedCodes, prevRenderedCodes ) ) { 180 return; 181 } 182 183 addedCodes = _.difference( nextRenderedCodes, prevRenderedCodes ); 184 removedCodes = _.difference( prevRenderedCodes, nextRenderedCodes ); 185 186 // Remove notifications that have been removed. 187 _.each( renderedNotificationContainers, function( renderedContainer, code ) { 188 if ( -1 !== _.indexOf( removedCodes, code ) ) { 189 renderedContainer.remove(); // @todo Consider slideUp as enhancement. 190 } 191 }); 192 193 // Add all notifications in the sorted order. 194 _.each( notifications, function( notification ) { 195 var notificationContainer = renderedNotificationContainers[ notification.code ]; 196 if ( notificationContainer ) { 197 listElement.append( notificationContainer ); 198 } else { 199 notificationContainer = $( notification.render() ); 200 listElement.append( notificationContainer ); // @todo Consider slideDown() as enhancement. 201 if ( wp.a11y ) { 202 wp.a11y.speak( notification.message, 'assertive' ); 203 } 204 } 205 }); 206 207 collection.trigger( 'rendered' ); 208 } 209 }); 4 210 5 211 /** … … 1884 2090 control.active = new api.Value(); 1885 2091 control.activeArgumentsQueue = []; 1886 control.notifications = new api.Values({ defaultConstructor: api.Notification }); 2092 control.notifications = new api.Notifications({ 2093 alt: control.altNotice 2094 }); 1887 2095 1888 2096 control.elements = []; … … 1974 2182 // After the control is embedded on the page, invoke the "ready" method. 1975 2183 control.deferred.embedded.done( function () { 1976 /* 1977 * Note that this debounced/deferred rendering is needed for two reasons: 1978 * 1) The 'remove' event is triggered just _before_ the notification is actually removed. 1979 * 2) Improve performance when adding/removing multiple notifications at a time. 1980 */ 1981 var debouncedRenderNotifications = _.debounce( function renderNotifications() { 1982 control.renderNotifications(); 2184 var renderNotifications = function() { 2185 control.notifications.render(); 2186 }; 2187 control.notifications.container = control.getNotificationsContainerElement(); 2188 control.notifications.bind( 'rendered', function() { 2189 var notifications = control.notifications.get(); 2190 control.container.toggleClass( 'has-notifications', 0 !== notifications.length ); 2191 control.container.toggleClass( 'has-error', 0 !== _.where( notifications, { type: 'error' } ).length ); 1983 2192 } ); 1984 control.notifications.bind( 'add', function( notification ) { 1985 wp.a11y.speak( notification.message, 'assertive' ); 1986 debouncedRenderNotifications(); 1987 } ); 1988 control.notifications.bind( 'remove', debouncedRenderNotifications ); 1989 control.renderNotifications(); 1990 2193 renderNotifications(); 2194 control.notifications.bind( 'change', _.debounce( renderNotifications ) ); 1991 2195 control.ready(); 1992 2196 }); … … 2092 2296 * of rendering notifications. 2093 2297 * 2298 * @deprecated in favor of `control.notifications.render()` 2094 2299 * @since 4.6.0 2095 2300 * @this {wp.customize.Control} … … 2097 2302 renderNotifications: function() { 2098 2303 var control = this, container, notifications, hasError = false; 2304 2305 if ( 'undefined' !== typeof console && console.warn ) { 2306 console.warn( '[DEPRECATED] wp.customize.Control.prototype.renderNotifications() is deprecated in favor of instantating a wp.customize.Notifications and calling its render() method.' ); 2307 } 2308 2099 2309 container = control.getNotificationsContainerElement(); 2100 2310 if ( ! container || ! container.length ) { … … 3427 3637 api.section = new api.Values({ defaultConstructor: api.Section }); 3428 3638 api.panel = new api.Values({ defaultConstructor: api.Panel }); 3639 3640 // Create the collection for global Notifications. 3641 api.notifications = new api.Notifications(); 3429 3642 3430 3643 /** … … 4502 4715 } ); 4503 4716 4717 // Remove notifications that were added due to save failures. 4718 api.notifications.each( function( notification ) { 4719 if ( notification.saveFailure ) { 4720 api.notifications.remove( notification.code ); 4721 } 4722 }); 4723 4504 4724 request.fail( function ( response ) { 4505 4725 … … 4519 4739 previewer.preview.iframe.show(); 4520 4740 } ); 4741 } else if ( response.code ) { 4742 api.notifications.add( response.code, new api.Notification( response.code, { 4743 message: response.message, 4744 type: 'error', 4745 dismissible: true, 4746 fromServer: true, 4747 saveFailure: true 4748 } ) ); 4749 } else { 4750 api.notifications.add( 'unknown_error', new api.Notification( 'unknown_error', { 4751 message: api.l10n.serverSaveError, 4752 type: 'error', 4753 dismissible: true, 4754 fromServer: true, 4755 saveFailure: true 4756 } ) ); 4521 4757 } 4522 4758 … … 4688 4924 values.bind( 'remove', debouncedReflowPaneContents ); 4689 4925 } ); 4926 4927 // Set up global notifications area. 4928 api.bind( 'ready', function setUpGlobalNotificationsArea() { 4929 var sidebar, containerHeight, containerInitialTop; 4930 api.notifications.container = $( '#customize-notifications-area' ); 4931 4932 api.notifications.bind( 'change', _.debounce( function() { 4933 api.notifications.render(); 4934 } ) ); 4935 4936 sidebar = $( '.wp-full-overlay-sidebar-content' ); 4937 api.notifications.bind( 'rendered', function updateSidebarTop() { 4938 sidebar.css( 'top', '' ); 4939 if ( 0 !== api.notifications.count() ) { 4940 containerHeight = api.notifications.container.outerHeight() + 1; 4941 containerInitialTop = parseInt( sidebar.css( 'top' ), 10 ); 4942 sidebar.css( 'top', containerInitialTop + containerHeight + 'px' ); 4943 } 4944 api.notifications.trigger( 'sidebarTopUpdated' ); 4945 }); 4946 4947 api.notifications.render(); 4948 }); 4690 4949 4691 4950 // Save and activated states … … 4972 5231 4973 5232 var scrollTop = parentContainer.scrollTop(), 4974 isScrollingUp = ( lastScrollTop ) ? scrollTop <= lastScrollTop : true; 4975 5233 scrollDirection; 5234 5235 if ( ! lastScrollTop ) { 5236 scrollDirection = 1; 5237 } else { 5238 if ( scrollTop === lastScrollTop ) { 5239 scrollDirection = 0; 5240 } else if ( scrollTop > lastScrollTop ) { 5241 scrollDirection = 1; 5242 } else { 5243 scrollDirection = -1; 5244 } 5245 } 4976 5246 lastScrollTop = scrollTop; 4977 positionStickyHeader( activeHeader, scrollTop, isScrollingUp ); 5247 if ( 0 !== scrollDirection ) { 5248 positionStickyHeader( activeHeader, scrollTop, scrollDirection ); 5249 } 4978 5250 }, 8 ) ); 5251 5252 // Update header position on sidebar layout change. 5253 api.notifications.bind( 'sidebarTopUpdated', function() { 5254 if ( activeHeader && activeHeader.element.hasClass( 'is-sticky' ) ) { 5255 activeHeader.element.css( 'top', parentContainer.css( 'top' ) ); 5256 } 5257 }); 4979 5258 4980 5259 // Release header element if it is sticky. … … 4991 5270 // Reset position of the sticky header. 4992 5271 resetStickyHeader = function( headerElement, headerParent ) { 4993 headerElement 4994 .removeClass( 'maybe-sticky is-in-view' ) 4995 .css( { 4996 width: '', 4997 top: '' 4998 } ); 4999 headerParent.css( 'padding-top', '' ); 5272 if ( headerElement.hasClass( 'is-in-view' ) ) { 5273 headerElement 5274 .removeClass( 'maybe-sticky is-in-view' ) 5275 .css( { 5276 width: '', 5277 top: '' 5278 } ); 5279 headerParent.css( 'padding-top', '' ); 5280 } 5000 5281 }; 5001 5282 … … 5024 5305 * @access private 5025 5306 * 5026 * @param {object} headerHeader.5027 * @param {number} scrollTopScroll top.5028 * @param { boolean} isScrollingUp Is scrolling up?5307 * @param {object} header - Header. 5308 * @param {number} scrollTop - Scroll top. 5309 * @param {number} scrollDirection - Scroll direction, negative number being up and positive being down. 5029 5310 * @returns {void} 5030 5311 */ 5031 positionStickyHeader = function( header, scrollTop, isScrollingUp) {5312 positionStickyHeader = function( header, scrollTop, scrollDirection ) { 5032 5313 var headerElement = header.element, 5033 5314 headerParent = header.parent, … … 5036 5317 maybeSticky = headerElement.hasClass( 'maybe-sticky' ), 5037 5318 isSticky = headerElement.hasClass( 'is-sticky' ), 5038 isInView = headerElement.hasClass( 'is-in-view' ); 5319 isInView = headerElement.hasClass( 'is-in-view' ), 5320 isScrollingUp = ( -1 === scrollDirection ); 5039 5321 5040 5322 // When scrolling down, gradually hide sticky header. … … 5079 5361 .addClass( 'is-sticky' ) 5080 5362 .css( { 5081 top: '',5363 top: parentContainer.css( 'top' ), 5082 5364 width: headerParent.outerWidth() + 'px' 5083 5365 } ); -
trunk/src/wp-admin/js/customize-widgets.js
r41249 r41374 551 551 control.widgetContentEmbedded = true; 552 552 553 // Update the notification container element now that the widget content has been embedded. 554 control.notifications.container = control.getNotificationsContainerElement(); 555 control.notifications.render(); 556 553 557 widgetContent = $( control.params.widget_content ); 554 558 control.container.find( '.widget-content:first' ).append( widgetContent ); -
trunk/src/wp-includes/class-wp-customize-manager.php
r41372 r41374 349 349 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_control_scripts' ) ); 350 350 351 // Render Panel, Section, and Control templates.351 // Render Common, Panel, Section, and Control templates. 352 352 add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_panel_templates' ), 1 ); 353 353 add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_section_templates' ), 1 ); … … 2356 2356 $response = array( 2357 2357 'setting_validities' => $setting_validities, 2358 'message' => sprintf( _n( 'There is %s invalid setting.', 'There are %s invalid settings.', $invalid_setting_count ), number_format_i18n( $invalid_setting_count ) ), 2358 /* translators: placeholder is number of invalid settings */ 2359 'message' => sprintf( _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', $invalid_setting_count ), number_format_i18n( $invalid_setting_count ) ), 2359 2360 ); 2360 2361 return new WP_Error( 'transaction_fail', '', $response ); … … 3184 3185 $control->print_template(); 3185 3186 } 3187 3188 ?> 3189 <script type="text/html" id="tmpl-customize-notification"> 3190 <li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.dismissible ? 'is-dismissible' : '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}"> 3191 {{{ data.message || data.code }}} 3192 <# if ( data.dismissible ) { #> 3193 <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php _e( 'Dismiss' ); ?></span></button> 3194 <# } #> 3195 </li> 3196 </script> 3197 3198 <?php 3199 /* The following template is obsolete in core but retained for plugins. */ 3186 3200 ?> 3187 3201 <script type="text/html" id="tmpl-customize-control-notifications"> -
trunk/src/wp-includes/js/customize-base.js
r41351 r41374 434 434 */ 435 435 remove: function( id ) { 436 var value; 437 438 if ( this.has( id ) ) { 439 value = this.value( id ); 436 var value = this.value( id ); 437 438 if ( value ) { 439 440 // Trigger event right before the element is removed from the collection. 440 441 this.trigger( 'remove', value ); 441 if ( value.extended( api.Value ) ) 442 443 if ( value.extended( api.Value ) ) { 442 444 value.unbind( this._change ); 445 } 443 446 delete value.parent; 444 447 } … … 446 449 delete this._value[ id ]; 447 450 delete this._deferreds[ id ]; 451 452 // Trigger removed event after the item has been eliminated from the collection. 453 if ( value ) { 454 this.trigger( 'removed', value ); 455 } 448 456 }, 449 457 … … 791 799 */ 792 800 api.Notification = api.Class.extend(/** @lends wp.customize.Notification.prototype */{ 801 802 /** 803 * Template function for rendering the notification. 804 * 805 * This will be populated with template option or else it will be populated with template from the ID. 806 * 807 * @since 4.9.0 808 * @var {Function} 809 */ 810 template: null, 811 812 /** 813 * ID for the template to render the notification. 814 * 815 * @since 4.9.0 816 * @var {string} 817 */ 818 templateId: 'customize-notification', 819 820 /** 821 * Initialize notification. 822 * 823 * @since 4.9.0 824 * 825 * @param {string} code - Notification code. 826 * @param {object} params - Notification parameters. 827 * @param {string} params.message - Message. 828 * @param {string} [params.type=error] - Type. 829 * @param {string} [params.setting] - Related setting ID. 830 * @param {Function} [params.template] - Function for rendering template. If not provided, this will come from templateId. 831 * @param {string} [params.templateId] - ID for template to render the notification. 832 * @param {boolean} [params.dismissible] - Whether the notification can be dismissed. 833 */ 793 834 initialize: function( code, params ) { 794 835 var _params; … … 800 841 fromServer: false, 801 842 data: null, 802 setting: null 843 setting: null, 844 template: null, 845 dismissible: false 803 846 }, 804 847 params … … 806 849 delete _params.code; 807 850 _.extend( this, _params ); 851 }, 852 853 /** 854 * Render the notification. 855 * 856 * @since 4.9.0 857 * 858 * @returns {jQuery} Notification container element. 859 */ 860 render: function() { 861 var notification = this, container, data; 862 if ( ! notification.template ) { 863 notification.template = wp.template( notification.templateId ); 864 } 865 data = _.extend( {}, notification, { 866 alt: notification.parent && notification.parent.alt 867 } ); 868 container = $( notification.template( data ) ); 869 870 if ( notification.dismissible ) { 871 container.find( '.notice-dismiss' ).on( 'click', function() { 872 if ( notification.parent ) { 873 notification.parent.remove( notification.code ); 874 } else { 875 container.remove(); 876 } 877 }); 878 } 879 880 return container; 808 881 } 809 882 }); -
trunk/src/wp-includes/script-loader.php
r41360 r41374 547 547 'expandSidebar' => _x( 'Show Controls', 'label for hide controls button without length constraints' ), 548 548 'untitledBlogName' => __( '(Untitled)' ), 549 'serverSaveError' => __( 'Failed connecting to the server. Please try saving again.' ), 549 550 // Used for overriding the file types allowed in plupload. 550 551 'allowedFiles' => __( 'Allowed Files' ), -
trunk/tests/qunit/index.html
r41206 r41374 210 210 <# } ); #> 211 211 </ul> 212 </script> 213 <script type="text/html" id="tmpl-customize-notification"> 214 <li class="notice notice-{{ data.type || 'info' }} {{ data.altNotice ? 'notice-alt' : '' }} {{ data.dismissible ? 'is-dismissible' : '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}"> 215 {{{ data.message || data.code }}} 216 <# if ( data.dismissible ) { #> 217 <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php _e( 'Dismiss' ); ?></span></button> 218 <# } #> 219 </li> 212 220 </script> 213 221 … … 387 395 <div hidden> 388 396 <div id="customize-preview"></div> 397 <div id="customize-notifications-test"><ul></ul></div> 389 398 </div> 390 399 -
trunk/tests/qunit/wp-admin/js/customize-base.js
r38810 r41374 3 3 jQuery( function( $ ) { 4 4 var FooSuperClass, BarSubClass, foo, bar, ConstructorTestClass, newConstructor, constructorTest, $mockElement, mockString, 5 firstInitialValue, firstValueInstance, wasCallbackFired, mockValueCallback;5 firstInitialValue, firstValueInstance, valuesInstance, wasCallbackFired, mockValueCallback; 6 6 7 7 module( 'Customize Base: Class' ); … … 160 160 }); 161 161 162 module( 'Customize Base: Values Class' ); 163 164 valuesInstance = new wp.customize.Values(); 165 166 test( 'Correct events are triggered when adding to or removing from Values collection', function() { 167 var hasFooOnAdd = false, 168 hasFooOnRemove = false, 169 hasFooOnRemoved = true, 170 valuePassedToAdd = false, 171 valuePassedToRemove = false, 172 valuePassedToRemoved = false, 173 wasEventFiredOnRemoval = false, 174 fooValue = new wp.customize.Value( 'foo' ); 175 176 // Test events when adding new value. 177 valuesInstance.bind( 'add', function( value ) { 178 hasFooOnAdd = valuesInstance.has( 'foo' ); 179 valuePassedToAdd = value; 180 } ); 181 valuesInstance.add( 'foo', fooValue ); 182 ok( hasFooOnAdd ); 183 equal( valuePassedToAdd.get(), fooValue.get() ); 184 185 // Test events when removing the value. 186 valuesInstance.bind( 'remove', function( value ) { 187 hasFooOnRemove = valuesInstance.has( 'foo' ); 188 valuePassedToRemove = value; 189 wasEventFiredOnRemoval = true; 190 } ); 191 valuesInstance.bind( 'removed', function( value ) { 192 hasFooOnRemoved = valuesInstance.has( 'foo' ); 193 valuePassedToRemoved = value; 194 wasEventFiredOnRemoval = true; 195 } ); 196 valuesInstance.remove( 'foo' ); 197 ok( hasFooOnRemove ); 198 equal( valuePassedToRemove.get(), fooValue.get() ); 199 ok( ! hasFooOnRemoved ); 200 equal( valuePassedToRemoved.get(), fooValue.get() ); 201 202 // Confirm no events are fired when nonexistent value is removed. 203 wasEventFiredOnRemoval = false; 204 valuesInstance.remove( 'bar' ); 205 ok( ! wasEventFiredOnRemoval ); 206 }); 207 162 208 module( 'Customize Base: Notification' ); 163 209 test( 'Notification object exists and has expected properties', function ( assert ) { -
trunk/tests/qunit/wp-admin/js/customize-controls.js
r38993 r41374 83 83 }; 84 84 85 module( 'Customizer notifications collection' ); 86 test( 'Notifications collection exists', function() { 87 ok( wp.customize.notifications ); 88 equal( wp.customize.notifications.defaultConstructor, wp.customize.Notification ); 89 } ); 90 91 test( 'Notification objects are rendered as part of notifications collection', function() { 92 var container = jQuery( '#customize-notifications-test' ), items, collection; 93 94 collection = new wp.customize.Notifications({ 95 container: container 96 }); 97 collection.add( 'mycode-1', new wp.customize.Notification( 'mycode-1' ) ); 98 collection.render(); 99 items = collection.container.find( 'li' ); 100 equal( items.length, 1 ); 101 equal( items.first().data( 'code' ), 'mycode-1' ); 102 103 collection.add( 'mycode-2', new wp.customize.Notification( 'mycode-2', { 104 dismissible: true 105 } ) ); 106 collection.render(); 107 items = collection.container.find( 'li' ); 108 equal( items.length, 2 ); 109 equal( items.first().data( 'code' ), 'mycode-2' ); 110 equal( items.last().data( 'code' ), 'mycode-1' ); 111 112 equal( items.first().find( '.notice-dismiss' ).length, 1 ); 113 equal( items.last().find( '.notice-dismiss' ).length, 0 ); 114 115 collection.remove( 'mycode-2' ); 116 collection.render(); 117 items = collection.container.find( 'li' ); 118 equal( items.length, 1 ); 119 equal( items.first().data( 'code' ), 'mycode-1' ); 120 121 collection.remove( 'mycode-1' ); 122 collection.render(); 123 ok( collection.container.is( ':hidden' ), 'Notifications area is hidden.' ); 124 } ); 125 85 126 module( 'Customizer Previewed Device' ); 86 127 test( 'Previewed device defaults to desktop.', function () { … … 145 186 assert.ok( notificationContainerElement.is( '.customize-control-notifications-container' ) ); 146 187 assert.equal( 0, notificationContainerElement.find( '> ul > li' ).length ); 147 assert.equal( 'none', notificationContainerElement.css( 'display') );188 assert.equal( 0, notificationContainerElement.height() ); 148 189 149 190 settingNotification = new wp.customize.Notification( 'setting_invalidity', 'Invalid setting' ); … … 153 194 154 195 // Note that renderNotifications is being called manually here since rendering normally happens asynchronously. 155 control. renderNotifications();196 control.notifications.render(); 156 197 157 198 assert.equal( 2, notificationContainerElement.find( '> ul > li' ).length ); … … 161 202 162 203 control.notifications.remove( controlOnlyNotification.code ); 163 control. renderNotifications();204 control.notifications.render(); 164 205 assert.equal( 1, notificationContainerElement.find( '> ul > li' ).length ); 165 206 assert.notEqual( 'none', notificationContainerElement.css( 'display' ) ); 166 207 167 208 control.settings['default'].notifications.remove( settingNotification.code ); 168 control. renderNotifications();209 control.notifications.render(); 169 210 assert.equal( 0, notificationContainerElement.find( '> ul > li' ).length ); 170 assert.ok( notificationContainerElement.is( ':animated' ) ); // It is being slid down.171 211 notificationContainerElement.stop().hide(); // Clean up. 172 212
Note: See TracChangeset
for help on using the changeset viewer.