diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css index c4df304ad5..c1aa128a34 100644 --- a/src/wp-admin/css/customize-controls.css +++ b/src/wp-admin/css/customize-controls.css @@ -789,10 +789,14 @@ p.customize-section-description { transition: .15s box-shadow linear; } -.customize-control-notifications-container li.notice { +#customize-controls .customize-control-notifications-container li.notice { list-style: none; margin: 0 0 6px 0; - padding: 4px 8px; + padding: 9px 14px; + overflow: hidden; +} +#customize-controls .customize-control-notifications-container .notice.is-dismissible { + padding-right: 38px; } .customize-control-notifications-container li.notice:last-child { @@ -815,26 +819,45 @@ p.customize-section-description { position: absolute; top: 46px; width: 100%; - max-height: 210px; - overflow-x: hidden; - overflow-y: auto; border-bottom: 1px solid #ddd; display: block; padding: 0; margin: 0; } +#customize-controls #customize-notifications-area, +#customize-controls .customize-section-title > .customize-control-notifications-container, +#customize-controls .panel-meta > .customize-control-notifications-container { + max-height: 210px; + overflow-x: hidden; + overflow-y: auto; +} + #customize-controls #customize-notifications-area > ul, -#customize-controls #customize-notifications-area .notice { +#customize-controls #customize-notifications-area .notice, +#customize-controls .panel-meta > .customize-control-notifications-container, +#customize-controls .panel-meta > .customize-control-notifications-container .notice, +#customize-controls .customize-section-title > .customize-control-notifications-container, +#customize-controls .customize-section-title > .customize-control-notifications-container .notice { margin: 0; } -#customize-controls #customize-notifications-area .notice { +#customize-controls .panel-meta > .customize-control-notifications-container, +#customize-controls .customize-section-title > .customize-control-notifications-container { + border-top: 1px solid #ddd; +} +#customize-controls #customize-notifications-area .notice, +#customize-controls .panel-meta > .customize-control-notifications-container .notice, +#customize-controls .customize-section-title > .customize-control-notifications-container .notice { padding: 9px 14px; } -#customize-controls #customize-notifications-area .notice.is-dismissible { +#customize-controls #customize-notifications-area .notice.is-dismissible, +#customize-controls .panel-meta > .customize-control-notifications-container .notice.is-dismissible, +#customize-controls .customize-section-title > .customize-control-notifications-container .notice.is-dismissible { padding-right: 38px; } -#customize-controls #customize-notifications-area .notice + .notice { +#customize-controls #customize-notifications-area .notice + .notice, +#customize-controls .panel-meta > .customize-control-notifications-container .notice + .notice, +#customize-controls .customize-section-title > .customize-control-notifications-container .notice + .notice { margin-top: 1px; } diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js index 4463e47b40..b483aea335 100644 --- a/src/wp-admin/js/customize-controls.js +++ b/src/wp-admin/js/customize-controls.js @@ -158,7 +158,7 @@ collection.container.toggle( 0 !== notifications.length ); // Short-circuit if there are no changes to the notifications. - if ( _.isEqual( notifications, collection.previousNotifications ) ) { + if ( collection.container.is( collection.previousContainer ) && _.isEqual( notifications, collection.previousNotifications ) ) { return; } @@ -185,6 +185,7 @@ }); collection.previousNotifications = notifications; + collection.previousContainer = collection.container; collection.trigger( 'rendered' ); } }); @@ -626,6 +627,7 @@ ); $.extend( container, options ); + container.notifications = new api.Notifications(); container.templateSelector = 'customize-' + container.containerType + '-' + container.params.type; container.container = $( container.params.content ); if ( 0 === container.container.length ) { @@ -657,6 +659,7 @@ }); container.deferred.embedded.done( function () { + container.setupNotifications(); container.attachEvents(); }); @@ -667,6 +670,39 @@ container.expanded.set( false ); }, + /** + * Get the element that will contain the notifications. + * + * @since 4.9.0 + * @returns {jQuery} Notification container element. + * @this {wp.customize.Control} + */ + getNotificationsContainerElement: function() { + var container = this; + return container.contentContainer.find( '.customize-control-notifications-container:first' ); + }, + + /** + * Set up notifications. + * + * @since 4.9.0 + * @returns {void} + */ + setupNotifications: function() { + var container = this, renderNotifications; + container.notifications.container = container.getNotificationsContainerElement(); + + // Render notifications when they change and when the construct is expanded. + renderNotifications = function() { + if ( container.expanded.get() ) { + container.notifications.render(); + } + }; + container.expanded.bind( renderNotifications ); + renderNotifications(); + container.notifications.bind( 'change', _.debounce( renderNotifications ) ); + }, + /** * @since 4.1.0 * @@ -2162,17 +2198,7 @@ // After the control is embedded on the page, invoke the "ready" method. control.deferred.embedded.done( function () { - var renderNotifications = function() { - control.notifications.render(); - }; - control.notifications.container = control.getNotificationsContainerElement(); - control.notifications.bind( 'rendered', function() { - var notifications = control.notifications.get(); - control.container.toggleClass( 'has-notifications', 0 !== notifications.length ); - control.container.toggleClass( 'has-error', 0 !== _.where( notifications, { type: 'error' } ).length ); - } ); - renderNotifications(); - control.notifications.bind( 'change', _.debounce( renderNotifications ) ); + control.setupNotifications(); control.ready(); }); }, @@ -2269,6 +2295,47 @@ return notificationsContainer; }, + /** + * Set up notifications. + * + * @since 4.9.0 + * @returns {void} + */ + setupNotifications: function() { + var control = this, renderNotificationsIfVisible, onSectionAssigned; + + control.notifications.container = control.getNotificationsContainerElement(); + + renderNotificationsIfVisible = function() { + var sectionId = control.section(); + if ( ! sectionId || ( api.section.has( sectionId ) && api.section( sectionId ).expanded() ) ) { + control.notifications.render(); + } + }; + + control.notifications.bind( 'rendered', function() { + var notifications = control.notifications.get(); + control.container.toggleClass( 'has-notifications', 0 !== notifications.length ); + control.container.toggleClass( 'has-error', 0 !== _.where( notifications, { type: 'error' } ).length ); + } ); + + onSectionAssigned = function( newSectionId, oldSectionId ) { + if ( oldSectionId && api.section.has( oldSectionId ) ) { + api.section( oldSectionId ).expanded.unbind( renderNotificationsIfVisible ); + } + if ( newSectionId ) { + api.section( newSectionId, function( section ) { + section.expanded.bind( renderNotificationsIfVisible ); + renderNotificationsIfVisible(); + }); + } + }; + + control.section.bind( onSectionAssigned ); + onSectionAssigned( control.section.get() ); + control.notifications.bind( 'change', _.debounce( renderNotificationsIfVisible ) ); + }, + /** * Render notifications. * @@ -5854,15 +5921,17 @@ api.control( 'header_video', function( headerVideoControl ) { headerVideoControl.deferred.embedded.done( function() { var toggleNotice = function() { - var section = api.section( headerVideoControl.section() ), notice; + var section = api.section( headerVideoControl.section() ), noticeCode = 'video_header_not_available'; if ( ! section ) { return; } - notice = section.container.find( '.header-video-not-currently-previewable:first' ); if ( headerVideoControl.active.get() ) { - notice.stop().slideUp( 'fast' ); + section.notifications.remove( noticeCode ); } else { - notice.stop().slideDown( 'fast' ); + section.notifications.add( noticeCode, new api.Notification( noticeCode, { + type: 'info', + message: api.l10n.videoHeaderNotice + } ) ); } }; toggleNotice(); diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index 7bd1489543..fa97e3f680 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -3928,10 +3928,6 @@ final class WP_Customize_Manager { $title = __( 'Header Media' ); $description = '
' . __( 'If you add a video, the image will be used as a fallback while the video loads.' ) . '
'; - // @todo Customizer sections should support having notifications just like controls do. See