Skip to content

Commit df391a9

Browse files
committed
Fix for #5120 - create menu only once and return that element from the widget method, put ui-autocomplete class on menu
1 parent d549ba6 commit df391a9

File tree

5 files changed

+64
-63
lines changed

5 files changed

+64
-63
lines changed

tests/unit/autocomplete/autocomplete_events.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ test("all events", function() {
2424
},
2525
close: function(event) {
2626
same(event.type, "autocompleteclose");
27-
same( $(".ui-menu").length, 1 );
27+
same( $(".ui-menu:visible").length, 1 );
2828
},
2929
select: function(event, ui) {
3030
same(event.type, "autocompleteselect");
3131
same(ui.item, {label:"java", value:"java"});
3232
},
3333
change: function(event) {
3434
same(event.type, "autocompletechange");
35-
same( $(".ui-menu").length, 0 );
35+
same( $(".ui-menu:visible").length, 0 );
3636
}
3737
});
3838
stop();
3939
ac.val("ja").keydown();
4040
setTimeout(function() {
41-
same( $(".ui-menu").length, 1 );
41+
same( $(".ui-menu:visible").length, 1 );
4242
ac.simulate("keydown", { keyCode: $.ui.keyCode.DOWN });
4343
ac.simulate("keydown", { keyCode: $.ui.keyCode.ENTER });
4444
start();
@@ -66,10 +66,10 @@ test("cancel search", function() {
6666
stop();
6767
ac.val("ja").keydown();
6868
setTimeout(function() {
69-
same( $(".ui-menu").length, 0 );
69+
same( $(".ui-menu:visible").length, 0 );
7070
ac.val("java").keydown();
7171
setTimeout(function() {
72-
same( $(".ui-menu").length, 1 );
72+
same( $(".ui-menu:visible").length, 1 );
7373
same( $(".ui-menu .ui-menu-item").length, 2 );
7474
start();
7575
}, 50);

tests/unit/autocomplete/autocomplete_methods.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ module("autocomplete: methods");
99
test("destroy", function() {
1010
var beforeHtml = $("#autocomplete").parent().html();
1111
var afterHtml = $("#autocomplete").autocomplete().autocomplete("destroy").parent().html();
12-
same( beforeHtml, afterHtml );
12+
// TODO can't use same, as that would insert the markup unescaped into the test results, screwing up other tests
13+
ok( beforeHtml == afterHtml );
1314
})
1415

1516
var data = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "pearl"];

tests/unit/autocomplete/autocomplete_options.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ test("delay", function() {
7171
});
7272
ac.val("ja").keydown();
7373

74-
same( $(".ui-menu").length, 0 );
74+
same( $(".ui-menu:visible").length, 0 );
7575

7676
// wait half a second for the default delay to open the menu
7777
stop();
7878
setTimeout(function() {
79-
same( $(".ui-menu").length, 1 );
79+
same( $(".ui-menu:visible").length, 1 );
8080
ac.autocomplete("destroy");
8181
start();
8282
}, 100);
@@ -87,11 +87,11 @@ test("minLength", function() {
8787
source: data
8888
});
8989
ac.autocomplete("search", "");
90-
same( $(".ui-menu").length, 0, "blank not enough for minLength: 1" );
90+
same( $(".ui-menu:visible").length, 0, "blank not enough for minLength: 1" );
9191

9292
ac.autocomplete("option", "minLength", 0);
9393
ac.autocomplete("search", "");
94-
same( $(".ui-menu").length, 1, "blank enough for minLength: 0" );
94+
same( $(".ui-menu:visible").length, 1, "blank enough for minLength: 0" );
9595
ac.autocomplete("destroy");
9696
});
9797

themes/base/ui.autocomplete.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* Autocomplete
22
----------------------------------*/
3-
.ui-autocomplete-menu { position: absolute; cursor: default; }
3+
.ui-autocomplete { position: absolute; cursor: default; }
44
.ui-autocomplete-loading { background: white url('images/ui-anim.basic.16x16.gif') right center no-repeat; }
55

66
/* workarounds */
7-
* html .ui-autocomplete-menu { width:1px; } /* without this, the menu expands to 100% in IE6 */
7+
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
88

99
/* Menu
1010
----------------------------------*/

ui/jquery.ui.autocomplete.js

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ $.widget( "ui.autocomplete", {
2121
_create: function() {
2222
var self = this;
2323
this.element
24-
.addClass( "ui-autocomplete" )
2524
.attr( "autocomplete", "off" )
2625
// TODO verify these actually work as intended
2726
.attr({
@@ -92,6 +91,44 @@ $.widget( "ui.autocomplete", {
9291
this.response = function() {
9392
return self._response.apply( self, arguments );
9493
};
94+
this.menu = $("<ul/>")
95+
.addClass( "ui-autocomplete" )
96+
.appendTo( this.element.parent() )
97+
.menu({
98+
focus: function( event, ui ) {
99+
var item = ui.item.data( "item.autocomplete" );
100+
if ( false !== self._trigger( "focus", null, { item: item } ) ) {
101+
// use value to match what will end up in the input
102+
self.element.val( item.value );
103+
}
104+
},
105+
selected: function( event, ui ) {
106+
var item = ui.item.data( "item.autocomplete" );
107+
if ( false !== self._trigger( "select", event, { item: item } ) ) {
108+
self.element.val( item.value );
109+
}
110+
self.close( event );
111+
self.previous = self.element.val();
112+
// only trigger when focus was lost (click on menu)
113+
if ( self.element[0] != document.activeElement ) {
114+
self.element.focus();
115+
}
116+
}
117+
})
118+
.zIndex( this.element.zIndex() + 1 )
119+
// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
120+
.css({ top: 0, left: 0 })
121+
.position({
122+
my: "left top",
123+
at: "left bottom",
124+
of: this.element,
125+
collision: "none"
126+
})
127+
.hide()
128+
.data( "menu" );
129+
if ( $.fn.bgiframe ) {
130+
menu.element.bgiframe();
131+
}
95132
},
96133

97134
destroy: function() {
@@ -170,10 +207,9 @@ $.widget( "ui.autocomplete", {
170207

171208
close: function( event ) {
172209
clearTimeout( this.closing );
173-
if ( this.menu ) {
210+
if ( this.menu.element.is(":visible") ) {
174211
this._trigger( "close", event );
175-
this.menu.element.remove();
176-
this.menu = null;
212+
this.menu.element.hide();
177213
}
178214
if ( this.previous != this.element.val() ) {
179215
this._trigger( "change", event );
@@ -200,59 +236,19 @@ $.widget( "ui.autocomplete", {
200236
},
201237

202238
_suggest: function( items ) {
203-
if (this.menu) {
204-
this.menu.element.remove();
205-
}
206-
var self = this,
207-
ul = $( "<ul></ul>" ),
208-
parent = this.element.parent();
209-
239+
this.menu.element.empty();
240+
var ul = this.menu.element;
210241
$.each( items, function( index, item ) {
211242
$( "<li></li>" )
212243
.data( "item.autocomplete", item )
213244
.append( "<a>" + item.label + "</a>" )
214245
.appendTo( ul );
215246
});
216-
this.menu = ul
217-
.addClass( "ui-autocomplete-menu" )
218-
.appendTo( parent )
219-
.menu({
220-
focus: function( event, ui ) {
221-
var item = ui.item.data( "item.autocomplete" );
222-
if ( false !== self._trigger( "focus", null, { item: item } ) ) {
223-
// use value to match what will end up in the input
224-
self.element.val( item.value );
225-
}
226-
},
227-
selected: function( event, ui ) {
228-
var item = ui.item.data( "item.autocomplete" );
229-
if ( false !== self._trigger( "select", event, { item: item } ) ) {
230-
self.element.val( item.value );
231-
}
232-
self.close( event );
233-
self.previous = self.element.val();
234-
// only trigger when focus was lost (click on menu)
235-
if ( self.element[0] != document.activeElement ) {
236-
self.element.focus();
237-
}
238-
}
239-
})
240-
.zIndex( this.element.zIndex() + 1 )
241-
// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
242-
.css({ top: 0, left: 0 })
243-
.position({
244-
my: "left top",
245-
at: "left bottom",
246-
of: this.element,
247-
collision: "none"
248-
})
249-
.data( "menu" );
247+
this.menu.refresh();
248+
this.menu.element.show();
250249
if ( ul.width() <= this.element.width() ) {
251250
ul.width( this.element.width() );
252251
}
253-
if ( $.fn.bgiframe ) {
254-
ul.bgiframe();
255-
}
256252
},
257253

258254
_move: function( direction, event ) {
@@ -270,8 +266,7 @@ $.widget( "ui.autocomplete", {
270266
},
271267

272268
widget: function() {
273-
// return empty jQuery object when menu isn't initialized yet
274-
return this.menu ? this.menu.element : $([]);
269+
return this.menu.element;
275270
}
276271
});
277272

@@ -316,7 +311,12 @@ $.widget("ui.menu", {
316311
e.preventDefault();
317312
self.select();
318313
});
319-
var items = this.element.children("li")
314+
this.refresh();
315+
},
316+
317+
refresh: function() {
318+
// don't refresh list items that are already adapted
319+
var items = this.element.children("li:not(.ui-menu-item)")
320320
.addClass("ui-menu-item")
321321
.attr("role", "menuitem");
322322

0 commit comments

Comments
 (0)