/[drupal]/drupal/misc/autocomplete.js
ViewVC logotype

Contents of /drupal/misc/autocomplete.js

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.34 - (show annotations) (download) (as text)
Sat Sep 5 12:03:31 2009 UTC (2 months, 3 weeks ago) by webchick
Branch: MAIN
CVS Tags: DRUPAL-7-0-UNSTABLE-10, DRUPAL-7-0-UNSTABLE-9, HEAD
Changes since 1.33: +3 -2 lines
File MIME type: text/javascript
#159762 by paul.lovvik and jp.stacey: Fixed Autocomplete errors from whitespace entry.
1 // $Id: autocomplete.js,v 1.33 2009/08/31 05:51:07 dries Exp $
2 (function ($) {
3
4 /**
5 * Attaches the autocomplete behavior to all required fields.
6 */
7 Drupal.behaviors.autocomplete = {
8 attach: function (context, settings) {
9 var acdb = [];
10 $('input.autocomplete', context).once('autocomplete', function () {
11 var uri = this.value;
12 if (!acdb[uri]) {
13 acdb[uri] = new Drupal.ACDB(uri);
14 }
15 var input = $('#' + this.id.substr(0, this.id.length - 13))
16 .attr('autocomplete', 'OFF')[0];
17 $(input.form).submit(Drupal.autocompleteSubmit);
18 new Drupal.jsAC(input, acdb[uri]);
19 });
20 }
21 };
22
23 /**
24 * Prevents the form from submitting if the suggestions popup is open
25 * and closes the suggestions popup when doing so.
26 */
27 Drupal.autocompleteSubmit = function () {
28 return $('#autocomplete').each(function () {
29 this.owner.hidePopup();
30 }).size() == 0;
31 };
32
33 /**
34 * An AutoComplete object.
35 */
36 Drupal.jsAC = function (input, db) {
37 var ac = this;
38 this.input = input;
39 this.db = db;
40
41 $(this.input)
42 .keydown(function (event) { return ac.onkeydown(this, event); })
43 .keyup(function (event) { ac.onkeyup(this, event); })
44 .blur(function () { ac.hidePopup(); ac.db.cancel(); });
45
46 };
47
48 /**
49 * Handler for the "keydown" event.
50 */
51 Drupal.jsAC.prototype.onkeydown = function (input, e) {
52 if (!e) {
53 e = window.event;
54 }
55 switch (e.keyCode) {
56 case 40: // down arrow.
57 this.selectDown();
58 return false;
59 case 38: // up arrow.
60 this.selectUp();
61 return false;
62 default: // All other keys.
63 return true;
64 }
65 };
66
67 /**
68 * Handler for the "keyup" event.
69 */
70 Drupal.jsAC.prototype.onkeyup = function (input, e) {
71 if (!e) {
72 e = window.event;
73 }
74 switch (e.keyCode) {
75 case 16: // shift.
76 case 17: // ctrl.
77 case 18: // alt.
78 case 20: // caps lock.
79 case 33: // page up.
80 case 34: // page down.
81 case 35: // end.
82 case 36: // home.
83 case 37: // left arrow.
84 case 38: // up arrow.
85 case 39: // right arrow.
86 case 40: // down arrow.
87 return true;
88
89 case 9: // tab.
90 case 13: // enter.
91 case 27: // esc.
92 this.hidePopup(e.keyCode);
93 return true;
94
95 default: // All other keys.
96 if (input.value.length > 0)
97 this.populatePopup();
98 else
99 this.hidePopup(e.keyCode);
100 return true;
101 }
102 };
103
104 /**
105 * Puts the currently highlighted suggestion into the autocomplete field.
106 */
107 Drupal.jsAC.prototype.select = function (node) {
108 this.input.value = $(node).data('autocompleteValue');
109 };
110
111 /**
112 * Highlights the next suggestion.
113 */
114 Drupal.jsAC.prototype.selectDown = function () {
115 if (this.selected && this.selected.nextSibling) {
116 this.highlight(this.selected.nextSibling);
117 }
118 else {
119 var lis = $('li', this.popup);
120 if (lis.size() > 0) {
121 this.highlight(lis.get(0));
122 }
123 }
124 };
125
126 /**
127 * Highlights the previous suggestion.
128 */
129 Drupal.jsAC.prototype.selectUp = function () {
130 if (this.selected && this.selected.previousSibling) {
131 this.highlight(this.selected.previousSibling);
132 }
133 };
134
135 /**
136 * Highlights a suggestion.
137 */
138 Drupal.jsAC.prototype.highlight = function (node) {
139 if (this.selected) {
140 $(this.selected).removeClass('selected');
141 }
142 $(node).addClass('selected');
143 this.selected = node;
144 };
145
146 /**
147 * Unhighlights a suggestion.
148 */
149 Drupal.jsAC.prototype.unhighlight = function (node) {
150 $(node).removeClass('selected');
151 this.selected = false;
152 };
153
154 /**
155 * Hides the autocomplete suggestions.
156 */
157 Drupal.jsAC.prototype.hidePopup = function (keycode) {
158 // Select item if the right key or mousebutton was pressed.
159 if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
160 this.input.value = $(this.selected).data('autocompleteValue');
161 }
162 // Hide popup.
163 var popup = this.popup;
164 if (popup) {
165 this.popup = null;
166 $(popup).fadeOut('fast', function () { $(popup).remove(); });
167 }
168 this.selected = false;
169 };
170
171 /**
172 * Positions the suggestions popup and starts a search.
173 */
174 Drupal.jsAC.prototype.populatePopup = function () {
175 // Show popup.
176 if (this.popup) {
177 $(this.popup).remove();
178 }
179 this.selected = false;
180 this.popup = $('<div id="autocomplete"></div>')[0];
181 this.popup.owner = this;
182 $(this.popup).css({
183 marginTop: this.input.offsetHeight + 'px',
184 width: (this.input.offsetWidth - 4) + 'px',
185 display: 'none'
186 });
187 $(this.input).before(this.popup);
188
189 // Do search.
190 this.db.owner = this;
191 this.db.search(this.input.value);
192 };
193
194 /**
195 * Fills the suggestion popup with any matches received.
196 */
197 Drupal.jsAC.prototype.found = function (matches) {
198 // If no value in the textfield, do not show the popup.
199 if (!this.input.value.length) {
200 return false;
201 }
202
203 // Prepare matches.
204 var ul = $('<ul></ul>');
205 var ac = this;
206 for (key in matches) {
207 $('<li></li>')
208 .html($('<div></div>').html(matches[key]))
209 .mousedown(function () { ac.select(this); })
210 .mouseover(function () { ac.highlight(this); })
211 .mouseout(function () { ac.unhighlight(this); })
212 .data('autocompleteValue', key)
213 .appendTo(ul);
214 }
215
216 // Show popup with matches, if any.
217 if (this.popup) {
218 if (ul.children().size()) {
219 $(this.popup).empty().append(ul).show();
220 }
221 else {
222 $(this.popup).css({ visibility: 'hidden' });
223 this.hidePopup();
224 }
225 }
226 };
227
228 Drupal.jsAC.prototype.setStatus = function (status) {
229 switch (status) {
230 case 'begin':
231 $(this.input).addClass('throbbing');
232 break;
233 case 'cancel':
234 case 'error':
235 case 'found':
236 $(this.input).removeClass('throbbing');
237 break;
238 }
239 };
240
241 /**
242 * An AutoComplete DataBase object.
243 */
244 Drupal.ACDB = function (uri) {
245 this.uri = uri;
246 this.delay = 300;
247 this.cache = {};
248 };
249
250 /**
251 * Performs a cached and delayed search.
252 */
253 Drupal.ACDB.prototype.search = function (searchString) {
254 var db = this;
255 this.searchString = searchString;
256
257 // See if this string needs to be searched for anyway.
258 searchString = searchString.replace(/^\s+|\s+$/, '');
259 if (searchString.length <= 0 ||
260 searchString.charAt(searchString.length - 1) == ',') {
261 return;
262 }
263
264 // See if this key has been searched for before.
265 if (this.cache[searchString]) {
266 return this.owner.found(this.cache[searchString]);
267 }
268
269 // Initiate delayed search.
270 if (this.timer) {
271 clearTimeout(this.timer);
272 }
273 this.timer = setTimeout(function () {
274 db.owner.setStatus('begin');
275
276 // Ajax GET request for autocompletion.
277 $.ajax({
278 type: 'GET',
279 url: db.uri + '/' + Drupal.encodePath(searchString),
280 dataType: 'json',
281 success: function (matches) {
282 if (typeof matches.status == 'undefined' || matches.status != 0) {
283 db.cache[searchString] = matches;
284 // Verify if these are still the matches the user wants to see.
285 if (db.searchString == searchString) {
286 db.owner.found(matches);
287 }
288 db.owner.setStatus('found');
289 }
290 },
291 error: function (xmlhttp) {
292 alert(Drupal.ajaxError(xmlhttp, db.uri));
293 }
294 });
295 }, this.delay);
296 };
297
298 /**
299 * Cancels the current autocomplete request.
300 */
301 Drupal.ACDB.prototype.cancel = function () {
302 if (this.owner) this.owner.setStatus('cancel');
303 if (this.timer) clearTimeout(this.timer);
304 this.searchString = '';
305 };
306
307 })(jQuery);

  ViewVC Help
Powered by ViewVC 1.1.2