From 8a5f5a72fd5a2c8f7db9d1522743041b00c86ec5 Mon Sep 17 00:00:00 2001 From: Matthew Hutton Date: Mon, 29 Aug 2011 17:48:11 +0100 Subject: [PATCH 1/2] Autocomplete: Added an option for not activating the autocomplete menu with the arrow keys. Fixed #7639 - Key up/key down in textarea's should optionally not toggle auto-complete. --- .../autocomplete/autocomplete_defaults.js | 1 + .../unit/autocomplete/autocomplete_options.js | 68 +++++++++++++++++++ ui/jquery.ui.autocomplete.js | 26 +++---- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/tests/unit/autocomplete/autocomplete_defaults.js b/tests/unit/autocomplete/autocomplete_defaults.js index ac83eaea491..db0a9f63cca 100644 --- a/tests/unit/autocomplete/autocomplete_defaults.js +++ b/tests/unit/autocomplete/autocomplete_defaults.js @@ -11,6 +11,7 @@ commonWidgetTests( "autocomplete", { collision: "none" }, source: null, + arrowsActivate: true, // callbacks change: null, diff --git a/tests/unit/autocomplete/autocomplete_options.js b/tests/unit/autocomplete/autocomplete_options.js index 8d11aa39992..7ff3e0dd783 100644 --- a/tests/unit/autocomplete/autocomplete_options.js +++ b/tests/unit/autocomplete/autocomplete_options.js @@ -88,6 +88,74 @@ asyncTest( "disabled", function() { }, 50 ); }); +asyncTest( "arrowsActivate is 'true' and pressing up causes the menu to be shown", function() { + arrowsActivateOpensMenuTest( true, true ); +}); + +asyncTest( "arrowsActivate is 'true' and pressing down causes the menu to be shown", function() { + arrowsActivateOpensMenuTest( true, false ); +}); + +asyncTest( "arrowsActivate is 'false' and pressing up doesn't cause the menu to be shown", function() { + arrowsActivateOpensMenuTest( false, true ); +}); + +asyncTest( "arrowsActivate is 'false' and pressing down doesn't cause the menu to be shown", function() { + arrowsActivateOpensMenuTest( false, false ); +}); + +function arrowsActivateOpensMenuTest( arrowsActivate, isKeyUp ) { + expect( 3 ); + var element = $( "#autocomplete" ).autocomplete({ + source: data, + delay: 0, + minLength: 0, + arrowsActivate: arrowsActivate + }); + menu = element.autocomplete( "widget" ); + ok( menu.is( ":hidden" ), "menu is hidden to start with" ); + element.simulate( "keydown", { keyCode: (isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN) } ); + + setTimeout(function() { + equal( menu.is( ":visible" ), arrowsActivate, "menu is visible after delay" ); + equal( menu.find('a.ui-state-focus').text(), "", "nothing should be initially selected" ); + start(); + }, 50 ); +} + +test( "Pressing up selects the previous search item when active", function() { + searchUpDownSelectsItemTest( true, true, "" ); +}); + +test( "Pressing down selects the next search item when active", function() { + searchUpDownSelectsItemTest( true, false, "javascript" ); +}); + +test( "Pressing up selects the previous search item when active", function() { + searchUpDownSelectsItemTest( false, true, "" ); +}); + +test( "Pressing down selects the next search item when active", function() { + searchUpDownSelectsItemTest( false, false, "javascript" ); +}); + +function searchUpDownSelectsItemTest( arrowsActivate, isKeyUp, itemThatShouldBeSelected ) { + expect( 2 ); + var element = $( "#autocomplete" ).autocomplete({ + source: data, + autoFocus: true, + delay: 0, + arrowsActivate: arrowsActivate + }); + menu = element.autocomplete( "widget" ); + + element.autocomplete("search", "a"); + + equal( menu.find('a.ui-state-focus').text(), "java", "Java should be initially selected" ); + element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); + equal( menu.find('a.ui-state-focus').text(), itemThatShouldBeSelected, "Check you've selected the expected value." ); +} + test( "minLength", function() { expect( 2 ); var element = $( "#autocomplete" ).autocomplete({ diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js index 3e016368227..0d11042b47b 100644 --- a/ui/jquery.ui.autocomplete.js +++ b/ui/jquery.ui.autocomplete.js @@ -32,6 +32,7 @@ $.widget( "ui.autocomplete", { collision: "none" }, source: null, + arrowsActivate: true, // callbacks change: null, @@ -83,15 +84,11 @@ $.widget( "ui.autocomplete", { break; case keyCode.UP: suppressKeyPress = true; - self._move( "previous", event ); - // prevent moving cursor to beginning of text field in some browsers - event.preventDefault(); + self._keyEvent( "previous", event ); break; case keyCode.DOWN: suppressKeyPress = true; - self._move( "next", event ); - // prevent moving cursor to end of text field in some browsers - event.preventDefault(); + self._keyEvent( "next", event ); break; case keyCode.ENTER: case keyCode.NUMPAD_ENTER: @@ -136,14 +133,10 @@ $.widget( "ui.autocomplete", { self._move( "nextPage", event ); break; case keyCode.UP: - self._move( "previous", event ); - // prevent moving cursor to beginning of text field in some browsers - event.preventDefault(); + self._keyEvent( "previous", event ); break; case keyCode.DOWN: - self._move( "next", event ); - // prevent moving cursor to end of text field in some browsers - event.preventDefault(); + self._keyEvent( "next", event ); break; } }) @@ -473,6 +466,15 @@ $.widget( "ui.autocomplete", { _value: function( value ) { return this.valueMethod.apply( this.element, arguments ); + }, + + _keyEvent: function( keyEvent, event ) { + if ( this.options.arrowsActivate || this.menu.active ) { + this._move( keyEvent, event ); + + // prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); + } } }); From e3093d7397a139914c0e6c22ad80119b30c4d4ee Mon Sep 17 00:00:00 2001 From: meh-cfl Date: Sun, 27 Nov 2011 12:16:16 +0000 Subject: [PATCH 2/2] Autocomplete: Removed arrowsActivate default and added code so that arrows don't activate menu in textarea/contenteditable. Fixed #7639 - Key up/key down in textarea's should optionally not toggle auto-complete. --- .../autocomplete/autocomplete_defaults.js | 1 - .../unit/autocomplete/autocomplete_events.js | 82 +++++++++++++++++++ .../unit/autocomplete/autocomplete_options.js | 68 --------------- ui/jquery.ui.autocomplete.js | 4 +- 4 files changed, 84 insertions(+), 71 deletions(-) diff --git a/tests/unit/autocomplete/autocomplete_defaults.js b/tests/unit/autocomplete/autocomplete_defaults.js index db0a9f63cca..ac83eaea491 100644 --- a/tests/unit/autocomplete/autocomplete_defaults.js +++ b/tests/unit/autocomplete/autocomplete_defaults.js @@ -11,7 +11,6 @@ commonWidgetTests( "autocomplete", { collision: "none" }, source: null, - arrowsActivate: true, // callbacks change: null, diff --git a/tests/unit/autocomplete/autocomplete_events.js b/tests/unit/autocomplete/autocomplete_events.js index 7b51ec4c08c..bd3d8b0d7af 100644 --- a/tests/unit/autocomplete/autocomplete_events.js +++ b/tests/unit/autocomplete/autocomplete_events.js @@ -176,4 +176,86 @@ asyncTest( "blur during remote search", function() { ac.val( "ro" ).keydown(); }); +asyncTest( "With an input pressing up causes the menu to be shown", function() { + arrowsActivateOpensMenuTest( "#autocomplete", true, true ); +}); + +asyncTest( "With an input pressing down causes the menu to be shown", function() { + arrowsActivateOpensMenuTest( "#autocomplete", false, true ); +}); + +asyncTest( "With a textarea pressing up doesn't cause the menu to be shown", function() { + arrowsActivateOpensMenuTest( "#autocomplete-textarea", true, false ); +}); + +asyncTest( "With a textarea pressing down doesn't cause the menu to be shown", function() { + arrowsActivateOpensMenuTest( "#autocomplete-textarea", false, false ); +}); + +asyncTest( "With a contenteditable pressing up doesn't cause the menu to be shown", function() { + arrowsActivateOpensMenuTest( "#autocomplete-contenteditable", true, false ); +}); + +asyncTest( "With a contenteditable pressing down doesn't cause the menu to be shown", function() { + arrowsActivateOpensMenuTest( "#autocomplete-contenteditable", false, false ); +}); + +function arrowsActivateOpensMenuTest( id, isKeyUp, isMenuVisible ) { + expect( 3 ); + var element = $( id ).autocomplete({ + source: data, + delay: 0, + minLength: 0 + }); + menu = element.autocomplete( "widget" ); + ok( menu.is( ":hidden" ), "menu is hidden to start with" ); + element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); + + setTimeout(function() { + equal( menu.is( ":visible" ), isMenuVisible, "menu is visible after delay" ); + equal( menu.find( "a.ui-state-focus" ).text(), "", "nothing should be initially selected" ); + start(); + }, 50 ); +} + +test( "Pressing up selects the previous search item when active with input", function() { + searchUpDownSelectsItemTest( "#autocomplete", true, "" ); +}); + +test( "Pressing down selects the next search item when active with input", function() { + searchUpDownSelectsItemTest( "#autocomplete", false, "JavaScript" ); +}); + +test( "Pressing up selects the previous search item when active with textarea", function() { + searchUpDownSelectsItemTest( "#autocomplete-textarea", true, "" ); +}); + +test( "Pressing down selects the next search item when active with textarea", function() { + searchUpDownSelectsItemTest( "#autocomplete-textarea", false, "JavaScript" ); +}); + +test( "Pressing up selects the previous search item when active with contenteditable", function() { + searchUpDownSelectsItemTest( "#autocomplete-contenteditable", true, "" ); +}); + +test( "Pressing down selects the next search item when active with contenteditable", function() { + searchUpDownSelectsItemTest( "#autocomplete-contenteditable", false, "JavaScript" ); +}); + +function searchUpDownSelectsItemTest( id, isKeyUp, itemThatShouldBeSelected ) { + expect( 2 ); + var element = $( id ).autocomplete({ + source: data, + autoFocus: true, + delay: 0 + }); + menu = element.autocomplete( "widget" ); + + element.autocomplete( "search", "a" ); + + equal( menu.find( "a.ui-state-focus" ).text(), "Java", "Java should be initially selected" ); + element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); + equal( menu.find( "a.ui-state-focus" ).text(), itemThatShouldBeSelected, "Check you've selected the expected value." ); +} + }( jQuery ) ); diff --git a/tests/unit/autocomplete/autocomplete_options.js b/tests/unit/autocomplete/autocomplete_options.js index c2ecd8535bd..114e9a42ba7 100644 --- a/tests/unit/autocomplete/autocomplete_options.js +++ b/tests/unit/autocomplete/autocomplete_options.js @@ -88,74 +88,6 @@ asyncTest( "disabled", function() { }, 50 ); }); -asyncTest( "arrowsActivate is 'true' and pressing up causes the menu to be shown", function() { - arrowsActivateOpensMenuTest( true, true ); -}); - -asyncTest( "arrowsActivate is 'true' and pressing down causes the menu to be shown", function() { - arrowsActivateOpensMenuTest( true, false ); -}); - -asyncTest( "arrowsActivate is 'false' and pressing up doesn't cause the menu to be shown", function() { - arrowsActivateOpensMenuTest( false, true ); -}); - -asyncTest( "arrowsActivate is 'false' and pressing down doesn't cause the menu to be shown", function() { - arrowsActivateOpensMenuTest( false, false ); -}); - -function arrowsActivateOpensMenuTest( arrowsActivate, isKeyUp ) { - expect( 3 ); - var element = $( "#autocomplete" ).autocomplete({ - source: data, - delay: 0, - minLength: 0, - arrowsActivate: arrowsActivate - }); - menu = element.autocomplete( "widget" ); - ok( menu.is( ":hidden" ), "menu is hidden to start with" ); - element.simulate( "keydown", { keyCode: (isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN) } ); - - setTimeout(function() { - equal( menu.is( ":visible" ), arrowsActivate, "menu is visible after delay" ); - equal( menu.find('a.ui-state-focus').text(), "", "nothing should be initially selected" ); - start(); - }, 50 ); -} - -test( "Pressing up selects the previous search item when active", function() { - searchUpDownSelectsItemTest( true, true, "" ); -}); - -test( "Pressing down selects the next search item when active", function() { - searchUpDownSelectsItemTest( true, false, "javascript" ); -}); - -test( "Pressing up selects the previous search item when active", function() { - searchUpDownSelectsItemTest( false, true, "" ); -}); - -test( "Pressing down selects the next search item when active", function() { - searchUpDownSelectsItemTest( false, false, "javascript" ); -}); - -function searchUpDownSelectsItemTest( arrowsActivate, isKeyUp, itemThatShouldBeSelected ) { - expect( 2 ); - var element = $( "#autocomplete" ).autocomplete({ - source: data, - autoFocus: true, - delay: 0, - arrowsActivate: arrowsActivate - }); - menu = element.autocomplete( "widget" ); - - element.autocomplete("search", "a"); - - equal( menu.find('a.ui-state-focus').text(), "java", "Java should be initially selected" ); - element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); - equal( menu.find('a.ui-state-focus').text(), itemThatShouldBeSelected, "Check you've selected the expected value." ); -} - test( "minLength", function() { expect( 2 ); var element = $( "#autocomplete" ).autocomplete({ diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js index 9be4cfd8c75..0658f456a89 100644 --- a/ui/jquery.ui.autocomplete.js +++ b/ui/jquery.ui.autocomplete.js @@ -32,7 +32,6 @@ $.widget( "ui.autocomplete", { collision: "none" }, source: null, - arrowsActivate: true, // callbacks change: null, @@ -491,7 +490,8 @@ $.widget( "ui.autocomplete", { }, _keyEvent: function( keyEvent, event ) { - if ( this.options.arrowsActivate || this.menu.active ) { + var target = $( event.target ); + if ( this.menu.activeMenu.is( ":visible" ) || !target.is( "textarea" ) && (typeof target.attr( "contenteditable" ) === "undefined" || target.attr( "contenteditable" ) === false )) { this._move( keyEvent, event ); // prevents moving cursor to beginning/end of the text field in some browsers