]> source.dussan.org Git - jquery-ui.git/commitdiff
Autocomplete: Rewrite with a delay instead of appending the live region
authorBen Mullins <benm@umich.edu>
Wed, 5 Jan 2022 10:35:34 +0000 (05:35 -0500)
committerGitHub <noreply@github.com>
Wed, 5 Jan 2022 10:35:34 +0000 (11:35 +0100)
This fixes the issue caused by https://bugs.jqueryui.com/ticket/9357.
We now empty the live region instead of appending to it, and we do so
after a brief timeout so the live region isn't updated on every mousemove
event or when quickly traversing through options.

Fixes gh-2002
Closes gh-2031

tests/unit/autocomplete/core.js
ui/widgets/autocomplete.js

index d78db3bb90e243b40ac9c8ec3c934a71814ec940..a2a36cb4c1cd837bcf15f5aa0ce1fdb15025b52c 100644 (file)
@@ -293,6 +293,7 @@ QUnit.test( "simultaneous searches (#9334)", function( assert ) {
 } );
 
 QUnit.test( "ARIA", function( assert ) {
+       var ready = assert.async();
        assert.expect( 13 );
        var element = $( "#autocomplete" ).autocomplete( {
                        source: [ "java", "javascript" ]
@@ -308,43 +309,51 @@ QUnit.test( "ARIA", function( assert ) {
                "Live region's role attribute must be status" );
 
        element.autocomplete( "search", "j" );
-       assert.equal( liveRegion.children().first().text(),
-               "2 results are available, use up and down arrow keys to navigate.",
-               "Live region for multiple values" );
+       setTimeout( function() {
+               assert.equal( liveRegion.children().first().text(),
+                       "2 results are available, use up and down arrow keys to navigate.",
+                       "Live region for multiple values" );
 
-       element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
-       assert.equal( liveRegion.children().filter( ":visible" ).text(), "java",
-               "Live region changed on keydown to announce the highlighted value" );
+               element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+               setTimeout( function() {
+                       assert.equal( liveRegion.children().filter( ":visible" ).text(), "java",
+                               "Live region changed on keydown to announce the highlighted value" );
 
-       element.one( "autocompletefocus", function( event ) {
-               event.preventDefault();
-       } );
-       element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
-       assert.equal( liveRegion.children().filter( ":visible" ).text(), "javascript",
-               "Live region updated when default focus is prevented" );
-
-       element.autocomplete( "search", "javas" );
-       assert.equal( liveRegion.children().filter( ":visible" ).text(),
-               "1 result is available, use up and down arrow keys to navigate.",
-               "Live region for one value" );
-
-       element.autocomplete( "search", "z" );
-       assert.equal( liveRegion.children().filter( ":visible" ).text(), "No search results.",
-               "Live region for no values" );
-
-       assert.equal( liveRegion.children().length, 5,
-               "Should be five children in the live region after the above" );
-       assert.equal( liveRegion.children().filter( ":visible" ).length, 1,
-               "Only one should be still visible" );
-       assert.ok( liveRegion.children().filter( ":visible" )[ 0 ] === liveRegion.children().last()[ 0 ],
-               "The last one should be the visible one" );
-
-       element.autocomplete( "destroy" );
-       assert.equal( liveRegion.parent().length, 0,
-               "The liveRegion should be detached after destroy" );
+                       element.one( "autocompletefocus", function( event ) {
+                               event.preventDefault();
+                       } );
+                       element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+                       setTimeout( function() {
+                               assert.equal( liveRegion.children().filter( ":visible" ).text(), "javascript",
+                                       "Live region updated when default focus is prevented" );
+                               element.autocomplete( "search", "javas" );
+                               setTimeout( function() {
+                                       assert.equal( liveRegion.children().filter( ":visible" ).text(),
+                                               "1 result is available, use up and down arrow keys to navigate.",
+                                               "Live region for one value" );
+                                       element.autocomplete( "search", "z" );
+                                       setTimeout( function() {
+                                               assert.equal( liveRegion.children().filter( ":visible" ).text(), "No search results.",
+                                                       "Live region for no values" );
+                                               assert.equal( liveRegion.children().length, 1,
+                                                       "Should be one child in the live region after the above" );
+                                               assert.equal( liveRegion.children().filter( ":visible" ).length, 1,
+                                                       "Only one should be still visible" );
+                                               assert.ok( liveRegion.children().filter( ":visible" )[ 0 ] === liveRegion.children().last()[ 0 ],
+                                                       "The last one should be the visible one" );
+                                               element.autocomplete( "destroy" );
+                                               assert.equal( liveRegion.parent().length, 0,
+                                                       "The liveRegion should be detached after destroy" );
+                                               ready();
+                                       }, 110 );
+                               }, 110 );
+                       }, 110 );
+               }, 110 );
+       }, 110 );
 } );
 
 QUnit.test( "ARIA, aria-label announcement", function( assert ) {
+       var ready = assert.async();
        assert.expect( 1 );
        $.widget( "custom.catcomplete", $.ui.autocomplete, {
                _renderMenu: function( ul, items ) {
@@ -361,8 +370,11 @@ QUnit.test( "ARIA, aria-label announcement", function( assert ) {
                liveRegion = element.catcomplete( "instance" ).liveRegion;
        element.catcomplete( "search", "a" );
        element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
-       assert.equal( liveRegion.children().filter( ":visible" ).text(), "People : anders andersson",
-               "Live region changed on keydown to announce the highlighted value's aria-label attribute" );
+       setTimeout( function() {
+               assert.equal( liveRegion.children().filter( ":visible" ).text(), "People : anders andersson",
+                       "Live region changed on keydown to announce the highlighted value's aria-label attribute" );
+               ready();
+       }, 110 );
 } );
 
 QUnit.test( "ARIA, init on detached input", function( assert ) {
index 4166029b2ed65974a5bb50cd49941ba809421cff..a7b6f52bd19c7a7f4e1157281443c7eda4f071ee 100644 (file)
@@ -66,6 +66,7 @@ $.widget( "ui.autocomplete", {
 
        requestIndex: 0,
        pending: 0,
+       liveRegionTimer: null,
 
        _create: function() {
 
@@ -267,8 +268,10 @@ $.widget( "ui.autocomplete", {
                                // Announce the value in the liveRegion
                                label = ui.item.attr( "aria-label" ) || item.value;
                                if ( label && String.prototype.trim.call( label ).length ) {
-                                       this.liveRegion.children().hide();
-                                       $( "<div>" ).text( label ).appendTo( this.liveRegion );
+                                       clearTimeout( this.liveRegionTimer );
+                                       this.liveRegionTimer = this._delay( function() {
+                                               this.liveRegion.html( $( "<div>" ).text( label ) );
+                                       }, 100 );
                                }
                        },
                        menuselect: function( event, ui ) {
@@ -663,8 +666,10 @@ $.widget( "ui.autocomplete", $.ui.autocomplete, {
                } else {
                        message = this.options.messages.noResults;
                }
-               this.liveRegion.children().hide();
-               $( "<div>" ).text( message ).appendTo( this.liveRegion );
+               clearTimeout( this.liveRegionTimer );
+               this.liveRegionTimer = this._delay( function() {
+                       this.liveRegion.html( $( "<div>" ).text( message ) );
+               }, 100 );
        }
 } );