Adds the precision that the site password has to be shorter than 10 characters
[platal.git] / htdocs / javascript / jquery.autocomplete.js
CommitLineData
baa8a594 1/* jQuery autocomplete Copyright Dylan Verheul <dylan@dyve.net>
2 * Licensed like jQuery, see http://docs.jquery.com/License
3 */
4
5$.autocomplete = function(input, options) {
6 // Create a link to self
7 var me = this;
8
9 // Create jQuery object for input element
10 var $input = $(input).attr("autocomplete", "off");;
11
12 // Apply inputClass if necessary
13 if (options.inputClass) $input.addClass(options.inputClass);
14
15 // Create results
16 var results = document.createElement("div");
17 // Create jQuery object for results
18 var $results = $(results);
19 // Set default values for results
20 var pos = findPos(input);
21 $results.hide().addClass(options.resultsClass).css({
22 position: "absolute",
23 top: (pos.y + input.offsetHeight) + "px",
24 left: pos.x + "px",
a94040d2 25 minWidth: $(input).width()
baa8a594 26 });
27 // Add to body element
28 $(input).parent().append(results);
29
30 input.autocompleter = me;
31 input.lastSelected = $input.val();
32
33 var timeout = null;
34 var prev = "";
35 var active = -1;
36 var cache = {};
37 var keyb = false;
38
39 $input
40 .keydown(function(e) {
41 switch(e.keyCode) {
42 case 38: // up
43 e.preventDefault();
44 moveSelect(-1);
45 break;
46 case 40: // down
47 e.preventDefault();
48 moveSelect(1);
49 break;
50 case 9: // tab
51 case 13: // return
52 if (selectCurrent()) {
53 e.preventDefault();
54 }
55 break;
56 default:
57 active = -1;
58 if (timeout) clearTimeout(timeout);
59 timeout = setTimeout(onChange, options.delay);
60 break;
61 }
62 })
63 .blur(function() {
64 hideResults();
65 });
66
67 hideResultsNow();
68
69 function onChange() {
70 var v = $input.val();
71 if (v == prev) return;
72 prev = v;
73 if (v.length >= options.minChars) {
74 $input.addClass(options.loadingClass);
75 requestData(v);
76 } else {
77 $input.removeClass(options.loadingClass);
78 $results.hide();
79 }
80 };
81
82 function moveSelect(step) {
83
84 var lis = $("li", results);
85 if (!lis) return;
86
87 active += step;
88
89 if (active < 0) {
90 active = 0;
91 } else if (active >= lis.size()) {
92 active = lis.size() - 1;
93 }
94
95 lis.removeClass("over");
96
97 $(lis[active]).addClass("over");
98
99 // Weird behaviour in IE
100 // if (lis[active] && lis[active].scrollIntoView) {
101 // lis[active].scrollIntoView(false);
102 // }
103
104 };
105
106 function selectCurrent() {
107 var li = $("li.over", results)[0];
108 if (!li) {
109 var $li = $("li", results);
110 if (options.selectOnly) {
111 if ($li.length == 1) li = $li[0];
112 } else if (options.selectFirst) {
113 li = $li[0];
114 }
115 }
116 if (li) {
117 selectItem(li);
118 return true;
119 } else {
120 return false;
121 }
122 };
123
124 function selectItem(li) {
125 if (!li) {
126 li = document.createElement("li");
127 li.extra = [];
128 li.selectValue = "";
129 }
130 var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML);
131 input.lastSelected = v;
132 prev = v;
133 $results.html("");
134 $input.val(v);
135 hideResultsNow();
136 if (options.onItemSelect) setTimeout(function() { options.onItemSelect(li) }, 1);
137 };
138
139 function hideResults() {
140 if (timeout) clearTimeout(timeout);
141 timeout = setTimeout(hideResultsNow, 200);
142 };
143
144 function hideResultsNow() {
145 if (timeout) clearTimeout(timeout);
146 $input.removeClass(options.loadingClass);
147 if ($results.is(":visible")) {
148 $results.hide();
149 }
150 if (options.mustMatch) {
151 var v = $input.val();
152 if (v != input.lastSelected) {
153 selectItem(null);
154 }
155 }
156 };
157
158 function receiveData(q, data) {
159 if (data) {
160 $input.removeClass(options.loadingClass);
161 results.innerHTML = "";
162 if ($.browser.msie) {
163 // we put a styled iframe behind the calendar so HTML SELECT elements don't show through
164 $results.append(document.createElement('iframe'));
165 }
a94040d2 166 var datasInDom = dataToDom(data);
167 results.appendChild(datasInDom);
baa8a594 168 $results.show();
a94040d2 169 // set size of ul smaller (for borders) but almost as big as div
170 $(datasInDom).width($results.width()-2);
baa8a594 171 } else {
172 hideResultsNow();
173 }
174 };
175
176 function parseData(data) {
177 if (!data) return null;
178 var parsed = [];
179 var rows = data.split(options.lineSeparator);
180 for (var i=0; i < rows.length; i++) {
181 var row = $.trim(rows[i]);
182 if (row) {
183 parsed[parsed.length] = row.split(options.cellSeparator);
184 }
185 }
186 return parsed;
187 };
188
189 function dataToDom(data) {
190 var ul = document.createElement("ul");
191 var num = data.length;
192 for (var i=0; i < num; i++) {
193 var row = data[i];
194 if (!row) continue;
195 var li = document.createElement("li");
196 if (options.formatItem) {
197 li.innerHTML = options.formatItem(row, i, num);
198 li.selectValue = row[0];
199 } else {
200 li.innerHTML = row[0];
201 }
202 var extra = null;
203 if (row.length > 1) {
204 extra = [];
205 for (var j=1; j < row.length; j++) {
206 extra[extra.length] = row[j];
207 }
208 }
209 li.extra = extra;
210 ul.appendChild(li);
211 $(li).hover(
212 function() { $("li", ul).removeClass("over"); $(this).addClass("over"); },
213 function() { $(this).removeClass("over"); }
214 ).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this) });
215 }
216 return ul;
217 };
218
219 function requestData(q) {
220 if (!options.matchCase) q = q.toLowerCase();
221 var data = options.cacheLength ? loadFromCache(q) : null;
222 if (data) {
223 receiveData(q, data);
224 } else {
225 $.get(makeUrl(q), function(data) {
226 data = parseData(data)
227 addToCache(q, data);
228 receiveData(q, data);
229 });
230 }
231 };
232
233 function makeUrl(q) {
234 var url = options.url + "?q=" + q;
235 for (var i in options.extraParams) {
236 url += "&" + i + "=" + options.extraParams[i];
237 }
238 return url;
239 };
240
241 function loadFromCache(q) {
242 if (!q) return null;
243 if (cache[q]) return cache[q];
244 if (options.matchSubset) {
245 for (var i = q.length - 1; i >= options.minChars; i--) {
246 var qs = q.substr(0, i);
247 var c = cache[qs];
248 if (c) {
249 var csub = [];
250 for (var j = 0; j < c.length; j++) {
251 var x = c[j];
252 var x0 = x[0];
253 if (matchSubset(x0, q)) {
254 csub[csub.length] = x;
255 }
256 }
257 return csub;
258 }
259 }
260 }
261 return null;
262 };
263
264 function matchSubset(s, sub) {
265 if (!options.matchCase) s = s.toLowerCase();
266 var i = s.indexOf(sub);
267 if (i == -1) return false;
268 return i == 0 || options.matchContains;
269 };
270
271 this.flushCache = function() {
272 cache = {};
273 };
274
275 this.setExtraParams = function(p) {
276 options.extraParams = p;
277 };
278
279 function addToCache(q, data) {
280 if (!data || !q || !options.cacheLength) return;
281 if (!cache.length || cache.length > options.cacheLength) {
282 cache = {};
283 cache.length = 1; // we know we're adding something
284 } else if (!cache[q]) {
285 cache.length++;
286 }
287 cache[q] = data;
288 };
289
290 function findPos(obj) {
291 var curleft = obj.offsetLeft || 0;
292 var curtop = obj.offsetTop || 0;
293 while (obj = obj.offsetParent) {
294 curleft += obj.offsetLeft
295 curtop += obj.offsetTop
296 }
297 return {x:curleft,y:curtop};
298 }
299}
300
301$.fn.autocomplete = function(url, options) {
302 // Make sure options exists
303 options = options || {};
304 // Set url as option
305 options.url = url;
306 // Set default values for required options
307 options.inputClass = options.inputClass || "ac_input";
308 options.resultsClass = options.resultsClass || "ac_results";
309 options.lineSeparator = options.lineSeparator || "\n";
310 options.cellSeparator = options.cellSeparator || "|";
311 options.minChars = options.minChars || 1;
312 options.delay = options.delay || 400;
313 options.matchCase = options.matchCase || 0;
314 options.matchSubset = typeof(options.matchSubset) != 'undefined' ? options.matchSubset : 1;
315 options.matchContains = options.matchContains || 0;
316 options.cacheLength = options.cacheLength || 1;
317 options.mustMatch = options.mustMatch || 0;
318 options.extraParams = options.extraParams || {};
319 options.loadingClass = options.loadingClass || "ac_loading";
320 options.selectFirst = options.selectFirst || false;
321 options.selectOnly = options.selectOnly || false;
322
323 this.each(function() {
324 var input = this;
325 new $.autocomplete(input, options);
326 });
327
328 // Don't break the chain
329 return this;
330}