diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css index 04e0b54798..c225569a4d 100644 --- a/src/wp-admin/css/customize-controls.css +++ b/src/wp-admin/css/customize-controls.css @@ -1409,6 +1409,11 @@ body.adding-widget .add-new-widget:before, overflow: auto; bottom: 0; width: 100%; + border-top: 1px solid #ddd; +} + +.no-widgets-found #available-widgets-list { + border-top: none; } #available-widgets-filter { @@ -1417,13 +1422,12 @@ body.adding-widget .add-new-widget:before, z-index: 1; width: 300px; background: #eee; - border-bottom: 1px solid #e5e5e5; } /* search field container */ #available-widgets-filter, #available-menu-items-search .accordion-section-title { - padding: 12px 15px; + padding: 13px 15px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; @@ -1431,8 +1435,101 @@ body.adding-widget .add-new-widget:before, #available-widgets-filter input, #available-menu-items-search input { - padding: 6px 10px; width: 100%; + height: 32px; + margin: 1px 0; + padding: 6px 30px; +} + +#available-widgets-filter input::-ms-clear, +#available-menu-items-search input::-ms-clear { + display: none; /* remove the "x" in IE, which conflicts with the "x" icon on button.clear-results */ +} + +#available-menu-items-search .search-icon, +#available-widgets-filter .search-icon { + display: block; + position: absolute; + top: 15px; /* 13 container padding +1 input margin +1 input border */ + left: 16px; + width: 30px; + height: 30px; + line-height: 28px; + text-align: center; + color: #72777c; +} + +#available-widgets-filter .clear-results, +#available-menu-items-search .clear-results { + position: absolute; + top: 15px; /* 13 container padding +1 input margin +1 input border */ + right: 16px; + width: 30px; + height: 30px; + padding: 0; + border: 0; + cursor: pointer; + background: none; + color: #a00; + text-decoration: none; + outline: 0; +} + +#available-widgets-filter .clear-results, +#available-menu-items-search .clear-results, +#available-menu-items-search.loading .clear-results.is-visible { + display: none; +} + +#available-widgets-filter .clear-results.is-visible, +#available-menu-items-search .clear-results.is-visible { + display: block; +} + +#available-widgets-filter .clear-results:before, +#available-menu-items-search .clear-results:before { + content: "\f335"; + font: normal 20px/1 dashicons; + vertical-align: middle; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +#available-widgets-filter .clear-results:hover, +#available-widgets-filter .clear-results:focus, +#available-menu-items-search .clear-results:hover, +#available-menu-items-search .clear-results:focus { + color: #dc3232; +} + +#available-widgets-filter .clear-results:focus, +#available-menu-items-search .clear-results:focus { + -webkit-box-shadow: + 0 0 0 1px #5b9dd9, + 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: + 0 0 0 1px #5b9dd9, + 0 0 2px 1px rgba(30, 140, 190, .8); +} + +#available-menu-items-search .search-icon:after, +#available-widgets-filter .search-icon:after { + content: "\f179"; + font: normal 20px/1 dashicons; + vertical-align: middle; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.no-widgets-found-message { + display: none; + margin: 0; + padding: 0 15px; + line-height: inherit; +} + +.no-widgets-found .no-widgets-found-message { + display: block; } #available-widgets .widget-top, @@ -1450,7 +1547,7 @@ body.adding-widget .add-new-widget:before, position: relative; padding: 20px 15px 20px 60px; background: #fff; - border-bottom: 1px solid #e5e5e5; + border-bottom: 1px solid #ddd; border-left: 4px solid #fff; cursor: pointer; display: none; @@ -1628,12 +1725,15 @@ body.adding-widget .add-new-widget:before, #available-widgets-filter { position: relative; width: 100%; - background: #fff; height: auto; - padding: 10px 15px; } #available-widgets-list { - top: 140px; + top: 130px; + } + + #available-menu-items-search .clear-results, + #available-menu-items-search .search-icon { + top: 85px; /* 70 section title height + 13 container padding +1 input margin +1 input border */ } } diff --git a/src/wp-admin/css/customize-nav-menus.css b/src/wp-admin/css/customize-nav-menus.css index eddc6c19de..c6dd7244c1 100644 --- a/src/wp-admin/css/customize-nav-menus.css +++ b/src/wp-admin/css/customize-nav-menus.css @@ -688,58 +688,17 @@ margin: 0 20px; } -#available-menu-items-search .clear-results { - position: absolute; - top: 18px; /* 12 container padding +1 input margin +1 input border +4 ( 4 is ( 28 input height - 20 button height ) / 2 ) */ - right: 20px; - width: 20px; - height: 20px; - padding: 0; - border: 0; - cursor: pointer; - background: none; - color: #a00; - text-decoration: none; - outline: 0; -} - -#available-menu-items-search .clear-results, -#available-menu-items-search.loading .clear-results.is-visible { - display: none; -} - -#available-menu-items-search .clear-results.is-visible { - display: block; -} - -.ie8 #available-menu-items-search.loading .clear-results:before { - content: ""; /* help IE8 redraw the pseudo element */ -} - -#available-menu-items-search .clear-results:before { - content: "\f335"; - font: normal 20px/1 dashicons; - vertical-align: middle; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -#available-menu-items-search .clear-results:hover, -#available-menu-items-search .clear-results:focus { - color: #f00; -} - #available-menu-items-search .spinner { position: absolute; - top: 18px; /* 12 container padding +1 input margin +1 input border +4 ( ( 28 input height - 20 button height ) / 2 ) */ - right: 20px; + top: 20px; /* 13 container padding +1 input margin +6 ( ( 32 input height - 20 spinner height ) / 2 ) */ + right: 21px; margin: 0 !important; } /* search results list */ #available-menu-items #available-menu-items-search .accordion-section-content { position: absolute; - left: 1px; + left: 0; top: 60px; /* below title div / search input */ bottom: 0px; /* 100% height that still triggers lazy load */ max-height: none; @@ -750,6 +709,11 @@ box-sizing: border-box; } +#available-menu-items-search .nothing-found { + /* Compensate the 1px top padding of the container. */ + margin-top: -1px; +} + #available-menu-items-search .accordion-section-title:after { display: none; } @@ -920,7 +884,6 @@ li.assigned-to-menu-location .add-new-menu-item { .customize-screen-options-toggle:focus:before, #customize-controls .customize-info .customize-help-toggle:focus:before, .wp-customizer button:focus .toggle-indicator:after, -#available-menu-items-search .clear-results:focus, .menu-delete:focus, .menu-item-bar .item-delete:focus:before, #available-menu-items .item-add:focus:before { @@ -937,19 +900,10 @@ li.assigned-to-menu-location .add-new-menu-item { #available-menu-items #available-menu-items-search .accordion-section-content { top: 63px; } - - #available-menu-items-search .spinner, - #available-menu-items-search .clear-results { - top: 20px; /* 12 container padding +1 input margin +1 input border +5.5 ( 5.5 rounded to 6 is ( 31 input height - 20 button height ) / 2 ) */ - } } @media screen and ( max-width: 640px ) { #available-menu-items #available-menu-items-search .accordion-section-content { - top: 133px; - } - - #available-menu-items-search .clear-results { - top: 90px; /* 70 section title height + 12 container padding +1 input margin +1 input border +5.5 ( 5.5 rounded to 6 is ( 31 input height - 20 button height ) / 2 ) */ + top: 130px; } } diff --git a/src/wp-admin/js/customize-nav-menus.js b/src/wp-admin/js/customize-nav-menus.js index 17793c741a..71052a1397 100644 --- a/src/wp-admin/js/customize-nav-menus.js +++ b/src/wp-admin/js/customize-nav-menus.js @@ -170,6 +170,7 @@ currentMenuControl: null, debounceSearch: null, $search: null, + $clearResults: null, searchTerm: '', rendered: false, pages: {}, @@ -185,6 +186,7 @@ } this.$search = $( '#menu-items-search' ); + this.$clearResults = this.$el.find( '.clear-results' ); this.sectionContent = this.$el.find( '.available-menu-items-list' ); this.debounceSearch = _.debounce( self.search, 500 ); @@ -202,8 +204,8 @@ } } ); - // Clear the search results. - $( '.clear-results' ).on( 'click', function() { + // Clear the search results and trigger a `keyup` event to fire a new search. + this.$clearResults.on( 'click', function() { self.$search.val( '' ).focus().trigger( 'keyup' ); } ); @@ -261,11 +263,11 @@ $otherSections.fadeOut( 100 ); $searchSection.find( '.accordion-section-content' ).slideDown( 'fast' ); $searchSection.addClass( 'open' ); - $searchSection.find( '.clear-results' ).addClass( 'is-visible' ); + this.$clearResults.addClass( 'is-visible' ); } else if ( '' === event.target.value ) { $searchSection.removeClass( 'open' ); $otherSections.show(); - $searchSection.find( '.clear-results' ).removeClass( 'is-visible' ); + this.$clearResults.removeClass( 'is-visible' ); } this.searchTerm = event.target.value; @@ -337,7 +339,7 @@ self.currentRequest.fail(function( data ) { // data.message may be undefined, for example when typing slow and the request is aborted. if ( data.message ) { - $content.empty().append( $( '

' ).text( data.message ) ); + $content.empty().append( $( '
  • ' ).text( data.message ) ); wp.a11y.speak( data.message ); } self.pages.search = -1; diff --git a/src/wp-admin/js/customize-widgets.js b/src/wp-admin/js/customize-widgets.js index 5c956d7e78..2799b82616 100644 --- a/src/wp-admin/js/customize-widgets.js +++ b/src/wp-admin/js/customize-widgets.js @@ -70,8 +70,7 @@ this.search( this.terms ); } - // If search is blank, show all themes - // Useful for resetting the views when you clean the input + // If search is blank, set all the widgets as they matched the search to reset the views. if ( this.terms === '' ) { this.each( function ( widget ) { widget.set( 'search_matched', true ); @@ -149,8 +148,6 @@ events: { 'input #widgets-search': 'search', 'keyup #widgets-search': 'search', - 'change #widgets-search': 'search', - 'search #widgets-search': 'search', 'focus .widget-tpl' : 'focus', 'click .widget-tpl' : '_submit', 'keypress .widget-tpl' : '_submit', @@ -163,18 +160,25 @@ // Cache sidebar control which has opened panel currentSidebarControl: null, $search: null, + $clearResults: null, + searchMatchesCount: null, initialize: function() { var self = this; this.$search = $( '#widgets-search' ); + this.$clearResults = this.$el.find( '.clear-results' ); + _.bindAll( this, 'close' ); this.listenTo( this.collection, 'change', this.updateList ); this.updateList(); + // Set the initial search count to the number of available widgets. + this.searchMatchesCount = this.collection.length; + // If the available widgets panel is open and the customize controls are // interacted with (i.e. available widgets panel is blurred) then close the // available widgets panel. Also close on back button click. @@ -185,6 +189,11 @@ } } ); + // Clear the search results and trigger a `keyup` event to fire a new search. + this.$clearResults.on( 'click', function() { + self.$search.val( '' ).focus().trigger( 'keyup' ); + } ); + // Close the panel if the URL in the preview changes api.previewer.bind( 'url', this.close ); }, @@ -194,6 +203,10 @@ var firstVisible; this.collection.doSearch( event.target.value ); + // Update the search matches count. + this.updateSearchMatchesCount(); + // Announce how many search results. + this.announceSearchMatches(); // Remove a widget from being selected if it is no longer visible if ( this.selected && ! this.selected.is( ':visible' ) ) { @@ -214,8 +227,38 @@ this.select( firstVisible ); } } + + // Toggle the clear search results button. + if ( '' !== event.target.value ) { + this.$clearResults.addClass( 'is-visible' ); + } else if ( '' === event.target.value ) { + this.$clearResults.removeClass( 'is-visible' ); + } + + // Set a CSS class on the search container when there are no search results. + if ( ! this.searchMatchesCount ) { + this.$el.addClass( 'no-widgets-found' ); + } else { + this.$el.removeClass( 'no-widgets-found' ); + } }, + // Update the count of the available widgets that have the `search_matched` attribute. + updateSearchMatchesCount: function() { + this.searchMatchesCount = this.collection.where({ search_matched: true }).length; + }, + + // Send a message to the aria-live region to announce how many search results. + announceSearchMatches: _.debounce( function() { + var message = l10n.widgetsFound.replace( '%d', this.searchMatchesCount ) ; + + if ( ! this.searchMatchesCount ) { + message = l10n.noWidgetsFound; + } + + wp.a11y.speak( message ); + }, 500 ), + // Changes visibility of available widgets updateList: function() { this.collection.each( function( widget ) { diff --git a/src/wp-includes/class-wp-customize-nav-menus.php b/src/wp-includes/class-wp-customize-nav-menus.php index 2487ab05f1..f102cd80f0 100644 --- a/src/wp-includes/class-wp-customize-nav-menus.php +++ b/src/wp-includes/class-wp-customize-nav-menus.php @@ -891,6 +891,7 @@ final class WP_Customize_Nav_Menus { + diff --git a/src/wp-includes/class-wp-customize-widgets.php b/src/wp-includes/class-wp-customize-widgets.php index 7db6631eb6..2189067704 100644 --- a/src/wp-includes/class-wp-customize-widgets.php +++ b/src/wp-includes/class-wp-customize-widgets.php @@ -733,7 +733,8 @@ final class WP_Customize_Widgets { 'reorderModeOn' => __( 'Reorder mode enabled' ), 'reorderModeOff' => __( 'Reorder mode closed' ), 'reorderLabelOn' => esc_attr__( 'Reorder widgets' ), - 'reorderLabelOff' => esc_attr__( 'Close reorder mode' ), + 'widgetsFound' => __( 'Number of widgets found: %d' ), + 'noWidgetsFound' => __( 'No widgets found.' ), ), 'tpl' => array( 'widgetReorderNav' => $widget_reorder_nav_tpl, @@ -777,7 +778,10 @@ final class WP_Customize_Widgets {
    - + + + +

    get_available_widgets() as $available_widget ): ?> @@ -785,6 +789,7 @@ final class WP_Customize_Widgets {
    +