r3322 committed - autocomplete: select autocomplete visual test; switched from keyup to ...
Revision: 3322
Author: joern.zaefferer
Date: Tue Sep 29 13:36:21 2009
Log: autocomplete: select autocomplete visual test; switched from keyup to
keypress to handle holding keys down (up/down curors); search event
cancellable; source option can return content instead of using response
callback; improved event triggering for close and change
http://code.google.com/p/jquery-ui/source/detail?r=3322
Added:
/branches/dev/tests/visual/autocomplete/select.html
Modified:
/branches/dev/tests/visual/autocomplete/default.html
/branches/dev/ui/jquery.ui.autocomplete.js
=======================================
--- /dev/null
+++ /branches/dev/tests/visual/autocomplete/select.html Tue Sep 29 13:36:21
2009
@@ -0,0 +1,98 @@
+<!doctype html>
+<html>
+<head>
+ <title>Autocomplete Visual Test: Default</title>
+ <link rel="stylesheet" href="../static.css" type="text/css" />
+ <link rel="stylesheet" href="../../../themes/base/ui.base.css"
type="text/css" />
+ <link rel="stylesheet" href="../../../themes/base/ui.theme.css"
type="text/css" title="ui-theme" />
+ <script type="text/javascript" src="../../../jquery-1.3.2.js"></script>
+ <script type="text/javascript"
src="../../../ui/jquery.ui.core.js"></script>
+ <script type="text/javascript"
src="../../../ui/jquery.ui.position.js"></script>
+ <script type="text/javascript"
src="../../../ui/jquery.ui.button.js"></script>
+ <script type="text/javascript"
src="../../../ui/jquery.ui.menu.js"></script>
+ <script type="text/javascript"
src="../../../ui/jquery.ui.autocomplete.js"></script>
+ <script type="text/javascript"
src="http://jqueryui.com/themeroller/themeswitchertool/"></script>
+ <script type="text/javascript">
+ (function($) {
+ $.widget("ui.selectAutocomplete", {
+ _init: function() {
+ var self = this;
+ var select = this.element.hide();
+ var input = $("<input/>").addClass("ui-widget ui-widget-content
ui-corner-left").insertAfter(select).autocomplete({
+ source: function(request) {
+ return select.children("option").map(function() {
+ var text = $(this).text();
+ return {
+ id: $(this).val(),
+ label: text,
+ result: text
+ };
+ });
+ },
+ change: function(e, ui) {
+ if (!ui.item) {
+ // remove invalid value, as it didn't match anything
+ $(this).val("");
+ return;
+ }
+ $(this).focus();
+ select.val(ui.item.id);
+ },
+ minLength: 0
+ });
+ $("<button/>")
+ .html('<span class="ui-icon ui-icon-triangle-1-s"/>')
+ .insertAfter(input)
+ .button().removeClass("ui-corner-all")
+ // TODO remove/replace once button is finished
+ .addClass("ui-corner-right ui-button-icon").css("margin-left", -1)
+ .click(function() {
+ input.autocomplete("search");
+ input.focus();
+ });
+ }
+ });
+
+ })(jQuery);
+
+ $(function() {
+ $('<div/>').css({
+ position: "absolute",
+ right: 10,
+ top: 10
+ }).appendTo(document.body).themeswitcher();
+
+ function log(message) {
+ $("<div/>").text(message).prependTo("#log");
+ $("#log").attr("scrollTop", 0);
+ }
+
+ $("select").selectAutocomplete();
+ $("input").focus();
+ });
+ </script>
+ <style>body { font-size:62.5%; }</style>
+</head>
+<body>
+
+<div class="ui-widget">
+ <label>Tags: </label>
+ <select>
+ <option>asp</option>
+ <option>c</option>
+ <option>c++</option>
+ <option>coldfusion</option>
+ <option>groovy</option>
+ <option>haskell</option>
+ <option>java</option>
+ <option>javascript</option>
+ <option>pearl</option>
+ <option>php</option>
+ <option>python</option>
+ <option>ruby</option>
+ <option>scala</option>
+ </select>
+</div>
+
+</body>
+</html>
=======================================
--- /branches/dev/tests/visual/autocomplete/default.html Tue Sep 29
12:30:10 2009
+++ /branches/dev/tests/visual/autocomplete/default.html Tue Sep 29
13:36:21 2009
@@ -44,15 +44,16 @@
}).focus();
});
</script>
+ <style>body { font-size:62.5%; }</style>
</head>
<body>
-<div>
+<div class="ui-widget">
<label>Tags: </label>
- <input id="tags" />
+ <input class="ui-widget ui-widget-content ui-corner-all" id="tags" />
</div>
-<div style="margin-top:2em; font-family:Arial">
+<div class="ui-widget" style="margin-top:2em; font-family:Arial">
Log:
<div id="log" style="height: 400px; width: 300px; overflow: auto;"
class="ui-widget-content"></div>
</div>
=======================================
--- /branches/dev/ui/jquery.ui.autocomplete.js Tue Sep 29 12:30:10 2009
+++ /branches/dev/ui/jquery.ui.autocomplete.js Tue Sep 29 13:36:21 2009
@@ -15,7 +15,8 @@
$.widget("ui.autocomplete", {
_init: function() {
var self = this;
- this.element.attr("autocomplete", "off").keyup(function(event) {
+ // keyup is triggered only once when hold down, keypress multiple times
+ this.element.attr("autocomplete", "off").keypress(function(event) {
switch(event.keyCode) {
case $.ui.keyCode.UP:
self.focusUp();
@@ -27,19 +28,20 @@
self.select();
break;
default:
- self.search();
+ // keypress is triggered before the input value is changed
+ setTimeout(function() {
+ self.search(event);
+ }, 13);
break;
}
}).focus(function() {
self.previous = self.element.val();
}).blur(function() {
- // TODO replace with a more reliable variant
- // without the timeout, the menu is removed before the click is
triggered on it, which also causes the blur
- setTimeout(function() {
+ // clicks on the menu (or a button to trigger a search) will cause a
blur event
+ // TODO try to implement this without a timeout, see clearTimeout in
search()
+ self.closing = setTimeout(function() {
+ // TODO pass {data: item} when a valid value is selected, even when
the suggestionlist wasn't used
self.close();
- if (self.previous != self.element.val()) {
- self._trigger("change");
- }
}, 150);
});
this.initSource();
@@ -68,29 +70,38 @@
search: function() {
var self = this;
+ clearTimeout(self.closing);
var value = this.element.val();
if (value.length >= this.options.minLength) {
- // TODO check return value to make search-event cancellable
- this._trigger("search");
- this.source({ term: value }, function response(content) {
+ if (this._trigger("search") === false)
+ return;
+ function response(content) {
if (content.length) {
self._trigger("open");
self.suggest(content);
} else {
self.close();
}
- });
+ }
+ // source can call response or return content directly
+ var result = this.source({ term: value }, response);
+ if (result) {
+ response(result);
+ }
} else {
this.close();
}
},
- close: function() {
- if (!this.menu)
- return;
- this._trigger("close");
- this.menu.remove();
- this.menu = null;
+ close: function(selected) {
+ if (this.menu) {
+ this._trigger("close");
+ this.menu.remove();
+ this.menu = null;
+ }
+ if (this.previous != this.element.val()) {
+ this._trigger("change", null, selected);
+ }
},
suggest: function(items) {
@@ -105,14 +116,12 @@
}).appendTo(document.body).menu({
focus: function(event, ui) {
self._trigger("focus", null, { item: ui.item.data("item.autocomplete")
});
+ // TODO update input value and revert back to the input when
focus "moves back" to the input
},
selected: function(event, ui) {
var data = ui.item.data("item.autocomplete");
self.element.val( data.result );
- self._trigger("close");
- self.menu.remove();
- self.menu = null;
- self._trigger("change", null, { item: data });
+ self.close({ item: data })
}
}).position({
my: "left top",