Fix for #5120 - create menu only once and return that element from the widget method, put ui-autocomplete class on menu

This commit is contained in:
Jörn Zaefferer 2010-02-02 14:04:50 +00:00
parent d549ba6d43
commit df391a998f
5 changed files with 64 additions and 63 deletions

View File

@ -24,7 +24,7 @@ test("all events", function() {
}, },
close: function(event) { close: function(event) {
same(event.type, "autocompleteclose"); same(event.type, "autocompleteclose");
same( $(".ui-menu").length, 1 ); same( $(".ui-menu:visible").length, 1 );
}, },
select: function(event, ui) { select: function(event, ui) {
same(event.type, "autocompleteselect"); same(event.type, "autocompleteselect");
@ -32,13 +32,13 @@ test("all events", function() {
}, },
change: function(event) { change: function(event) {
same(event.type, "autocompletechange"); same(event.type, "autocompletechange");
same( $(".ui-menu").length, 0 ); same( $(".ui-menu:visible").length, 0 );
} }
}); });
stop(); stop();
ac.val("ja").keydown(); ac.val("ja").keydown();
setTimeout(function() { setTimeout(function() {
same( $(".ui-menu").length, 1 ); same( $(".ui-menu:visible").length, 1 );
ac.simulate("keydown", { keyCode: $.ui.keyCode.DOWN }); ac.simulate("keydown", { keyCode: $.ui.keyCode.DOWN });
ac.simulate("keydown", { keyCode: $.ui.keyCode.ENTER }); ac.simulate("keydown", { keyCode: $.ui.keyCode.ENTER });
start(); start();
@ -66,10 +66,10 @@ test("cancel search", function() {
stop(); stop();
ac.val("ja").keydown(); ac.val("ja").keydown();
setTimeout(function() { setTimeout(function() {
same( $(".ui-menu").length, 0 ); same( $(".ui-menu:visible").length, 0 );
ac.val("java").keydown(); ac.val("java").keydown();
setTimeout(function() { setTimeout(function() {
same( $(".ui-menu").length, 1 ); same( $(".ui-menu:visible").length, 1 );
same( $(".ui-menu .ui-menu-item").length, 2 ); same( $(".ui-menu .ui-menu-item").length, 2 );
start(); start();
}, 50); }, 50);

View File

@ -9,7 +9,8 @@ module("autocomplete: methods");
test("destroy", function() { test("destroy", function() {
var beforeHtml = $("#autocomplete").parent().html(); var beforeHtml = $("#autocomplete").parent().html();
var afterHtml = $("#autocomplete").autocomplete().autocomplete("destroy").parent().html(); var afterHtml = $("#autocomplete").autocomplete().autocomplete("destroy").parent().html();
same( beforeHtml, afterHtml ); // TODO can't use same, as that would insert the markup unescaped into the test results, screwing up other tests
ok( beforeHtml == afterHtml );
}) })
var data = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "pearl"]; var data = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "pearl"];

View File

@ -71,12 +71,12 @@ test("delay", function() {
}); });
ac.val("ja").keydown(); ac.val("ja").keydown();
same( $(".ui-menu").length, 0 ); same( $(".ui-menu:visible").length, 0 );
// wait half a second for the default delay to open the menu // wait half a second for the default delay to open the menu
stop(); stop();
setTimeout(function() { setTimeout(function() {
same( $(".ui-menu").length, 1 ); same( $(".ui-menu:visible").length, 1 );
ac.autocomplete("destroy"); ac.autocomplete("destroy");
start(); start();
}, 100); }, 100);
@ -87,11 +87,11 @@ test("minLength", function() {
source: data source: data
}); });
ac.autocomplete("search", ""); ac.autocomplete("search", "");
same( $(".ui-menu").length, 0, "blank not enough for minLength: 1" ); same( $(".ui-menu:visible").length, 0, "blank not enough for minLength: 1" );
ac.autocomplete("option", "minLength", 0); ac.autocomplete("option", "minLength", 0);
ac.autocomplete("search", ""); ac.autocomplete("search", "");
same( $(".ui-menu").length, 1, "blank enough for minLength: 0" ); same( $(".ui-menu:visible").length, 1, "blank enough for minLength: 0" );
ac.autocomplete("destroy"); ac.autocomplete("destroy");
}); });

View File

@ -1,10 +1,10 @@
/* Autocomplete /* Autocomplete
----------------------------------*/ ----------------------------------*/
.ui-autocomplete-menu { position: absolute; cursor: default; } .ui-autocomplete { position: absolute; cursor: default; }
.ui-autocomplete-loading { background: white url('images/ui-anim.basic.16x16.gif') right center no-repeat; } .ui-autocomplete-loading { background: white url('images/ui-anim.basic.16x16.gif') right center no-repeat; }
/* workarounds */ /* workarounds */
* html .ui-autocomplete-menu { width:1px; } /* without this, the menu expands to 100% in IE6 */ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/* Menu /* Menu
----------------------------------*/ ----------------------------------*/

View File

@ -21,7 +21,6 @@ $.widget( "ui.autocomplete", {
_create: function() { _create: function() {
var self = this; var self = this;
this.element this.element
.addClass( "ui-autocomplete" )
.attr( "autocomplete", "off" ) .attr( "autocomplete", "off" )
// TODO verify these actually work as intended // TODO verify these actually work as intended
.attr({ .attr({
@ -92,6 +91,44 @@ $.widget( "ui.autocomplete", {
this.response = function() { this.response = function() {
return self._response.apply( self, arguments ); return self._response.apply( self, arguments );
}; };
this.menu = $("<ul/>")
.addClass( "ui-autocomplete" )
.appendTo( this.element.parent() )
.menu({
focus: function( event, ui ) {
var item = ui.item.data( "item.autocomplete" );
if ( false !== self._trigger( "focus", null, { item: item } ) ) {
// use value to match what will end up in the input
self.element.val( item.value );
}
},
selected: function( event, ui ) {
var item = ui.item.data( "item.autocomplete" );
if ( false !== self._trigger( "select", event, { item: item } ) ) {
self.element.val( item.value );
}
self.close( event );
self.previous = self.element.val();
// only trigger when focus was lost (click on menu)
if ( self.element[0] != document.activeElement ) {
self.element.focus();
}
}
})
.zIndex( this.element.zIndex() + 1 )
// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
.css({ top: 0, left: 0 })
.position({
my: "left top",
at: "left bottom",
of: this.element,
collision: "none"
})
.hide()
.data( "menu" );
if ( $.fn.bgiframe ) {
menu.element.bgiframe();
}
}, },
destroy: function() { destroy: function() {
@ -170,10 +207,9 @@ $.widget( "ui.autocomplete", {
close: function( event ) { close: function( event ) {
clearTimeout( this.closing ); clearTimeout( this.closing );
if ( this.menu ) { if ( this.menu.element.is(":visible") ) {
this._trigger( "close", event ); this._trigger( "close", event );
this.menu.element.remove(); this.menu.element.hide();
this.menu = null;
} }
if ( this.previous != this.element.val() ) { if ( this.previous != this.element.val() ) {
this._trigger( "change", event ); this._trigger( "change", event );
@ -200,59 +236,19 @@ $.widget( "ui.autocomplete", {
}, },
_suggest: function( items ) { _suggest: function( items ) {
if (this.menu) { this.menu.element.empty();
this.menu.element.remove(); var ul = this.menu.element;
}
var self = this,
ul = $( "<ul></ul>" ),
parent = this.element.parent();
$.each( items, function( index, item ) { $.each( items, function( index, item ) {
$( "<li></li>" ) $( "<li></li>" )
.data( "item.autocomplete", item ) .data( "item.autocomplete", item )
.append( "<a>" + item.label + "</a>" ) .append( "<a>" + item.label + "</a>" )
.appendTo( ul ); .appendTo( ul );
}); });
this.menu = ul this.menu.refresh();
.addClass( "ui-autocomplete-menu" ) this.menu.element.show();
.appendTo( parent )
.menu({
focus: function( event, ui ) {
var item = ui.item.data( "item.autocomplete" );
if ( false !== self._trigger( "focus", null, { item: item } ) ) {
// use value to match what will end up in the input
self.element.val( item.value );
}
},
selected: function( event, ui ) {
var item = ui.item.data( "item.autocomplete" );
if ( false !== self._trigger( "select", event, { item: item } ) ) {
self.element.val( item.value );
}
self.close( event );
self.previous = self.element.val();
// only trigger when focus was lost (click on menu)
if ( self.element[0] != document.activeElement ) {
self.element.focus();
}
}
})
.zIndex( this.element.zIndex() + 1 )
// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
.css({ top: 0, left: 0 })
.position({
my: "left top",
at: "left bottom",
of: this.element,
collision: "none"
})
.data( "menu" );
if ( ul.width() <= this.element.width() ) { if ( ul.width() <= this.element.width() ) {
ul.width( this.element.width() ); ul.width( this.element.width() );
} }
if ( $.fn.bgiframe ) {
ul.bgiframe();
}
}, },
_move: function( direction, event ) { _move: function( direction, event ) {
@ -270,8 +266,7 @@ $.widget( "ui.autocomplete", {
}, },
widget: function() { widget: function() {
// return empty jQuery object when menu isn't initialized yet return this.menu.element;
return this.menu ? this.menu.element : $([]);
} }
}); });
@ -316,7 +311,12 @@ $.widget("ui.menu", {
e.preventDefault(); e.preventDefault();
self.select(); self.select();
}); });
var items = this.element.children("li") this.refresh();
},
refresh: function() {
// don't refresh list items that are already adapted
var items = this.element.children("li:not(.ui-menu-item)")
.addClass("ui-menu-item") .addClass("ui-menu-item")
.attr("role", "menuitem"); .attr("role", "menuitem");