r769 - in branches/1.7: . tests tests/visual/autocomplete
Author: pazu2k@gmail.com
Date: Sat Oct 4 21:37:16 2008
New Revision: 769
Modified:
branches/1.7/tests/autocomplete.html
branches/1.7/tests/visual/autocomplete/index.html
branches/1.7/ui.autocomplete.js
Log:
Autocomplete: refactored code (unstable). Note: this is only a start - more
refactoring planned.
Modified: branches/1.7/tests/autocomplete.html
==============================================================================
--- branches/1.7/tests/autocomplete.html (original)
+++ branches/1.7/tests/autocomplete.html Sat Oct 4 21:37:16 2008
@@ -4,9 +4,9 @@
<link rel="stylesheet" href="qunit/testsuite.css" type="text/css"
media="screen">
- <script type="text/javascript" src="../jquery-1.2.6.js"></script>
- <script type="text/javascript" src="../ui/ui.core.js"></script>
- <script type="text/javascript" src="../ui/ui.autocomplete.js"></script>
+ <script type="text/javascript"
src="../../../trunk/jquery-1.2.6.js"></script>
+ <script type="text/javascript"
src="../../../trunk/ui/ui.core.js"></script>
+ <script type="text/javascript" src="../ui.autocomplete.js"></script>
<script type="text/javascript" src="qunit/testrunner.js"></script>
<script type="text/javascript" src="simulate/jquery.simulate.js"></script>
Modified: branches/1.7/tests/visual/autocomplete/index.html
==============================================================================
--- branches/1.7/tests/visual/autocomplete/index.html (original)
+++ branches/1.7/tests/visual/autocomplete/index.html Sat Oct 4 21:37:16
2008
@@ -4,13 +4,13 @@
<title>jQuery Autocomplete Plugin</title>
-<script type="text/javascript" src="../../../jquery-1.2.6.js"></script>
-<script type="text/javascript" src="../../../ui/ui.core.js"></script>
-<script type="text/javascript"
src="../../../ui/ui.autocomplete.js"></script>
+<script type="text/javascript"
src="../../../../../trunk/jquery-1.2.6.js"></script>
+<script type="text/javascript"
src="../../../../../trunk/ui/ui.core.js"></script>
+<script type="text/javascript" src="../../../ui.autocomplete.js"></script>
-<script type='text/javascript' src='localdata.js'></script>
+<script type="text/javascript" src="localdata.js"></script>
<link rel="stylesheet" type="text/css" href="main.css" />
-<link rel="stylesheet" href="../../../themes/default/ui.all.css"
type="text/css" media="screen" title="no title" charset="utf-8">
+<link rel="stylesheet"
href="../../../../../trunk/themes/default/ui.all.css" type="text/css"
media="screen" title="no title" charset="utf-8">
<script type="text/javascript">
$().ready(function() {
Modified: branches/1.7/ui.autocomplete.js
==============================================================================
--- branches/1.7/ui.autocomplete.js (original)
+++ branches/1.7/ui.autocomplete.js Sat Oct 4 21:37:16 2008
@@ -17,410 +17,420 @@
_init: function() {
$.extend(this.options, {
- delay: this.options.url ? $.Autocompleter.defaults.delay : 10,
+ delay: this.options.url ? this.options.delay : 10,
max: !this.options.scroll ? 10 : 150,
highlight: this.options.highlight || function(value) { return value; },
// if highlight is set to false, replace it with a do-nothing function
formatMatch: this.options.formatMatch || this.options.formatItem // if
the formatMatch option is not specified, then use formatItem for backwards
compatibility
});
-
- new $.Autocompleter(this.element[0], this.options);
-
- },
-
- result: function(handler) {
- return this.element.bind("result", handler);
- },
- search: function(handler) {
- return this.element.trigger("search", [handler]);
- },
- flushCache: function() {
- return this.element.trigger("flushCache");
- },
- setData: function(key, value){
- return this.element.trigger("setOptions", [{ key: value }]);
- },
- destroy: function() {
- return this.element.trigger("unautocomplete");
- }
-
-});
-$.Autocompleter = function(input, options) {
-
- var KEY = {
- UP: 38,
- DOWN: 40,
- DEL: 46,
- TAB: 9,
- RETURN: 13,
- ESC: 27,
- COMMA: 188,
- PAGEUP: 33,
- PAGEDOWN: 34,
- BACKSPACE: 8
- };
-
- // Create $ object for input element
- var $input =
$(input).attr("autocomplete", "off").addClass(options.inputClass);
- if(options.result) $input.bind('result.autocomplete', options.result);
-
- var timeout;
- var previousValue = "";
- var cache = $.Autocompleter.Cache(options);
- var hasFocus = 0;
- var lastKeyPressCode;
- var config = {
- mouseDownOnSelect: false
- };
- var select = $.Autocompleter.Select(options, input, selectCurrent,
config);
-
- var blockSubmit;
-
- // prevent form submit in opera when selecting with return key
- $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
- if (blockSubmit) {
- blockSubmit = false;
- return false;
+ var input = this.element[0],
+ options = this.options,
+ // Create $ object for input element
+ $input =
$(input).attr("autocomplete", "off").addClass(options.inputClass),
+ KEY = $.keyCode,
+ previousValue = "",
+ cache = $.ui.autocomplete.cache(options),
+ hasFocus = 0,
+ config = {
+ mouseDownOnSelect: false
+ },
+ timeout,
+ blockSubmit,
+ lastKeyPressCode,
+ select = $.ui.autocomplete.select(options, input, selectCurrent,
config);
+
+ if(options.result) {
+ $input.bind('result.autocomplete', options.result);
}
- });
-
- // only opera doesn't trigger keydown multiple times while pressed,
others don't work with keypress at all
- $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete",
function(event) {
- // track last key pressed
- lastKeyPressCode = event.keyCode;
- switch(event.keyCode) {
-
- case KEY.UP:
- event.preventDefault();
- if ( select.visible() ) {
- select.prev();
- } else {
- onChange(0, true);
+
+ // prevent form submit in opera when selecting with return key
+ $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+ if (blockSubmit) {
+ blockSubmit = false;
+ return false;
+ }
+ });
+
+ // only opera doesn't trigger keydown multiple times while pressed,
others don't work with keypress at all
+ $input.bind(($.browser.opera ? "keypress" : "keydown")
+ ".autocomplete", function(e) {
+ // track last key pressed
+ lastKeyPressCode = e.keyCode;
+ switch(e.keyCode) {
+
+ case KEY.UP:
+ e.preventDefault();
+ if ( select.visible() ) {
+ select.prev();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.DOWN:
+ e.preventDefault();
+ if ( select.visible() ) {
+ select.next();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGE_UP:
+ e.preventDefault();
+ if ( select.visible() ) {
+ select.pageUp();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGE_DOWN:
+ e.preventDefault();
+ if ( select.visible() ) {
+ select.pageDown();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ // matches also semicolon
+ case options.multiple && $.trim(options.multipleSeparator) == "," &&
KEY.COMMA:
+ case KEY.TAB:
+ case KEY.ENTER:
+ if( selectCurrent() ) {
+ // stop default to prevent a form submit, Opera needs special
handling
+ e.preventDefault();
+ blockSubmit = true;
+ return false;
+ }
+ break;
+
+ case KEY.ESCAPE:
+ select.hide();
+ break;
+
+ default:
+ clearTimeout(timeout);
+ timeout = setTimeout(onChange, options.delay);
+ break;
+ }
+ }).focus(function(){
+ // track whether the field has focus, we shouldn't process any
+ // results if the field no longer has focus
+ hasFocus++;
+ }).blur(function() {
+ hasFocus = 0;
+ if (!config.mouseDownOnSelect) {
+ hideResults();
+ }
+ }).click(function() {
+ // show select when clicking in a focused field
+ if ( hasFocus++ > 1 && !select.visible() ) {
+ onChange(0, true);
+ }
+ }).bind("search", function() {
+ // TODO why not just specifying both arguments?
+ var fn = (arguments.length > 1) ? arguments[1] : null;
+ function findValueCallback(q, data) {
+ var result;
+ if( data && data.length ) {
+ for (var i=0; i < data.length; i++) {
+ if( data[i].result.toLowerCase() == q.toLowerCase() ) {
+ result = data[i];
+ break;
+ }
+ }
}
- break;
-
- case KEY.DOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.next();
- } else {
- onChange(0, true);
+ if( typeof fn == "function" ) fn(result);
+ else $input.trigger("result", result && [result.data, result.value]);
+ }
+ $.each(trimWords($input.val()), function(i, value) {
+ request(value, findValueCallback, findValueCallback);
+ });
+ }).bind("flushCache", function() {
+ cache.flush();
+ }).bind("setOptions", function() {
+ $.extend(options, arguments[1]);
+ // if we've updated the data, repopulate
+ if ( "data" in arguments[1] )
+ cache.populate();
+ }).bind("unautocomplete", function() {
+ select.unbind();
+ $input.unbind();
+ $(input.form).unbind(".autocomplete");
+ });
+
+
+ // Private methods
+ function selectCurrent() {
+ var selected = select.selected();
+ if( !selected )
+ return false;
+
+ var v = selected.result;
+ previousValue = v;
+
+ if ( options.multiple ) {
+ var words = trimWords($input.val());
+ if ( words.length > 1 ) {
+ v = words.slice(0, words.length - 1).join( options.multipleSeparator
) + options.multipleSeparator + v;
}
- break;
+ v += options.multipleSeparator;
+ }
- case KEY.PAGEUP:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageUp();
- } else {
- onChange(0, true);
- }
- break;
+ $input.val(v);
+ hideResultsNow();
+ $input.trigger("result", [selected.data, selected.value]);
+ return true;
+ };
+
+ function onChange(crap, skipPrevCheck) {
+ if( lastKeyPressCode == $.keyCode.DELETE ) {
+ select.hide();
+ return;
+ }
- case KEY.PAGEDOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageDown();
- } else {
- onChange(0, true);
- }
- break;
+ var currentValue = $input.val();
- // matches also semicolon
- case options.multiple && $.trim(options.multipleSeparator) == "," &&
KEY.COMMA:
- case KEY.TAB:
- case KEY.RETURN:
- if( selectCurrent() ) {
- // stop default to prevent a form submit, Opera needs special handling
- event.preventDefault();
- blockSubmit = true;
- return false;
- }
- break;
+ if ( !skipPrevCheck && currentValue == previousValue )
+ return;
- case KEY.ESC:
- select.hide();
- break;
+ previousValue = currentValue;
- default:
- clearTimeout(timeout);
- timeout = setTimeout(onChange, options.delay);
- break;
- }
- }).focus(function(){
- // track whether the field has focus, we shouldn't process any
- // results if the field no longer has focus
- hasFocus++;
- }).blur(function() {
- hasFocus = 0;
- if (!config.mouseDownOnSelect) {
- hideResults();
- }
- }).click(function() {
- // show select when clicking in a focused field
- if ( hasFocus++ > 1 && !select.visible() ) {
- onChange(0, true);
- }
- }).bind("search", function() {
- // TODO why not just specifying both arguments?
- var fn = (arguments.length > 1) ? arguments[1] : null;
- function findValueCallback(q, data) {
- var result;
- if( data && data.length ) {
- for (var i=0; i < data.length; i++) {
- if( data[i].result.toLowerCase() == q.toLowerCase() ) {
- result = data[i];
- break;
- }
- }
+ currentValue = lastWord(currentValue);
+ if ( currentValue.length >= options.minChars) {
+ $input.addClass(options.loadingClass);
+ if (!options.matchCase)
+ currentValue = currentValue.toLowerCase();
+ request(currentValue, receiveData, hideResultsNow);
+ } else {
+ stopLoading();
+ select.hide();
}
- if( typeof fn == "function" ) fn(result);
- else $input.trigger("result", result && [result.data, result.value]);
- }
- $.each(trimWords($input.val()), function(i, value) {
- request(value, findValueCallback, findValueCallback);
-