source: trunk/www.guidonia.net/wp/wp-content/plugins/simple-tags/2.7/inc/js/bcomplete.js@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 12.6 KB
Line 
1RegExp.escape = function(text)
2{
3 if (!arguments.callee.sRE)
4 {
5 var specials = [
6 '/', '.', '*', '+', '?', '|',
7 '(', ')', '[', ']', '{', '}', '\\'
8 ];
9
10 arguments.callee.sRE = new RegExp(
11 '(\\' + specials.join('|\\') + ')', 'g'
12 );
13 }
14
15 return text.replace(arguments.callee.sRE,'\\$1');
16};
17
18var BComplete = Class.create();
19BComplete.prototype =
20{
21 MAX_VISIBLE : 8,
22 TIMER_TICK : 10,
23 CANCEL_SUBMISSION_TIMEOUT : 10,
24
25 initialize : function(element,max)
26 {
27 if(max)
28 {
29 this.MAX_VISIBLE = max;
30 }
31
32 this.data = new Array();
33 this.element = $(element);
34 if(!this.element)
35 {
36 throw("BComplete: The specified <input> element does not exist.");
37 }
38
39 this.element.setAttribute("autocomplete","off");
40 Element.addClassName(this.element,"bcomplete-field");
41
42 this.visible = false;
43 this.cancelSubmit = false;
44 this.scroll = 0;
45 this.selectedIndex = -1;
46 this.matches = new Array();
47
48 this.popup = document.createElement("div");
49 Element.hide(this.popup);
50 this.popup.className = "bcomplete-popup";
51 document.body.appendChild(this.popup);
52
53 this.upButton = document.createElement("div");
54 this.upButton.className = "up-button";
55 this.popup.appendChild(this.upButton);
56
57 this.listItems = new Array();
58 for(var i=0;i<this.MAX_VISIBLE;i++)
59 {
60 var item = document.createElement("div");
61 this.listItems[i] = item ;
62 item.className = "item";
63 this.popup.appendChild(item);
64 item.autocomplete = this;
65 item.number = i;
66
67 item.onclick = this.onItemClick;
68 item.onmouseover = this.onItemOn;
69 item.onmouseout = this.onItemOff;
70 }
71
72 this.downButton = document.createElement("div");
73 this.downButton.className = "down-button";
74 this.popup.appendChild(this.downButton);
75
76 Event.observe(this.element,"keypress",
77 this.onKeyPress.bindAsEventListener(this));
78 Event.observe(this.element,"keydown",
79 this.onKeyDown.bindAsEventListener(this));
80 Event.observe(this.upButton,"click",
81 this.onUpButton.bindAsEventListener(this));
82 Event.observe(this.downButton,"click",
83 this.onDownButton.bindAsEventListener(this));
84 Event.observe(document,"click",
85 this.onWindowClick.bindAsEventListener(this));
86
87 this.onTick = this.onTick.bind(this);
88 this.onSubmit = this.onSubmit.bind(this);
89
90 // look for parent <form>
91 var parentForm = this.element.parentNode;
92 while(parentForm)
93 {
94 if(parentForm.tagName.toLowerCase() == "form")
95 break;
96
97 parentForm = parentForm.parentNode;
98 }
99
100 // capture submit event for parent <form>
101 var me = this;
102 if(parentForm)
103 {
104 var oldHandler = parentForm.onsubmit;
105 parentForm.onsubmit = function()
106 {
107 if(oldHandler)
108 return (oldHandler() && me.onSubmit());
109 else
110 return me.onSubmit();
111 };
112 }
113 },
114
115 addItem : function(item)
116 {
117 this.data[this.data.length] = item;
118 this.data.sort();
119 },
120
121 setData : function(data)
122 {
123 this.data = data;
124 data.sort();
125 },
126
127 loadData : function(url)
128 {
129 var me = this;
130 var success = function(request)
131 {
132 try
133 {
134 var data = eval(request.responseText);
135 if(typeof data == "object")
136 {
137 me.setData(data);
138 }
139 }
140 catch(exception)
141 {
142 throw("BComplete: Invalid data format.");
143 }
144 };
145
146 var request = new Ajax.Request(url,
147 { method: 'get', onSuccess: success });
148 },
149
150 findMatches : function(text)
151 {
152 var matches = new Array();
153
154 // Modifications for multiples values
155 var exp = new RegExp(",?[^,]*$" , "i");
156 m = text.match(exp);
157 text = m[0].replace(/^[,\s]+|\s+$/g,"");
158
159 // Strict search (old) (must start with...)
160 // var expression = new RegExp("^"+ RegExp.escape(text),"i");
161 // Cool search
162 var expression = new RegExp(RegExp.escape(text),"i");
163
164 for(var i=0;i<this.data.length;i++) {
165 if(this.data[i].match(expression)) {
166 matches[matches.length] = this.data[i];
167 }
168 }
169
170 return matches;
171 },
172
173 temporarilyDisableSubmission : function()
174 {
175 this.cancelSubmit = true;
176 var me = this;
177 var revert = function()
178 {
179 me.cancelSubmit = false;
180 };
181
182 setTimeout(revert,this.CANCEL_SUBMISSION_TIMEOUT);
183 },
184
185 onWindowClick : function(event)
186 {
187 var element = Event.element(event);
188
189 var parent = element;
190 while(parent)
191 {
192 if(parent == this.element || parent == this.popup ||
193 parent == this.showAllButton)
194 {
195 return;
196 }
197
198 parent = parent.parentNode;
199 }
200
201 this.hide();
202 },
203
204 onUpButton : function(event)
205 {
206 this.selectedIndex = -1;
207 this.scroll--;
208 if(this.scroll < 0)
209 this.scroll = 0;
210
211 this.show();
212 Event.stop(event);
213 this.element.focus();
214 },
215
216 onDownButton : function(event)
217 {
218 this.selectedIndex = -1;
219 this.scroll++;
220 if(this.scroll > (this.matches.length - this.MAX_VISIBLE))
221 this.scroll = (this.matches.length - this.MAX_VISIBLE);
222
223 this.show();
224 Event.stop(event);
225 this.element.focus();
226 },
227
228 onKeyDown : function(event)
229 {
230 if(event.keyCode == 13 && this.visible)
231 {
232 this.temporarilyDisableSubmission();
233 this.select();
234 Event.stop(event);
235 return false;
236 }
237 },
238
239 showAll : function()
240 {
241 this.matches = this.findMatches('');
242 this.element.focus();
243 this.show();
244 },
245
246 onKeyPress : function(event)
247 {
248 if(event.keyCode == Event.KEY_TAB)
249 {
250 if(this.visible)
251 {
252 this.select();
253 Event.stop(event);
254 return false;
255 }
256 }
257 else if(event.keyCode == Event.KEY_DOWN)
258 {
259 this.selectedIndex++;
260 if(this.selectedIndex < this.scroll)
261 this.selectedIndex = this.scroll;
262
263 if(this.selectedIndex >= this.matches.length)
264 this.selectedIndex = this.matches.length - 1;
265
266 if(this.scroll <= (this.selectedIndex - this.MAX_VISIBLE))
267 this.scroll++;
268
269 if(this.matches.length == 0)
270 {
271 this.matches = this.findMatches(this.element.value);
272 }
273
274 this.show();
275 Event.stop(event);
276 return;
277 }
278 else if(event.keyCode == Event.KEY_UP)
279 {
280 this.selectedIndex--;
281 if(this.selectedIndex <= -1 && this.scroll <= 0)
282 {
283 this.selectedIndex = -1;
284 this.hide();
285 Event.stop(event);
286 return;
287 }
288
289 if(this.selectedIndex <= -1)
290 this.selectedIndex = this.scroll + (this.MAX_VISIBLE - 1);
291
292 if(this.scroll > this.selectedIndex)
293 this.scroll--;
294
295 this.show();
296 Event.stop(event);
297 return;
298 }
299 else if(event.keyCode != 13)
300 {
301 if(this.timerId)
302 clearTimeout(this.timerId);
303
304 this.timerId = setTimeout(this.onTick,this.TIMER_TICK);
305 }
306 },
307
308 onTick : function()
309 {
310 this.selectedIndex = -1;
311 this.scroll = 0;
312 if(this.element.value != '')
313 {
314 this.matches = this.findMatches(this.element.value);
315 if(this.matches.length > 0)
316 this.show();
317 else
318 this.hide();
319 }
320 else
321 {
322 this.hide();
323 }
324 },
325
326 onSubmit : function()
327 {
328 if(this.cancelSubmit)
329 {
330 this.cancelSubmit = false;
331 return false;
332 }
333 else
334 {
335 return true;
336 }
337 },
338
339 onItemOn : function()
340 {
341 for(var i=0;i<this.autocomplete.MAX_VISIBLE;i++)
342 Element.removeClassName(this.autocomplete.listItems[i],"selected");
343
344 Element.addClassName(this,"selected");
345 this.autocomplete.selectedIndex = this.number;
346 },
347
348 onItemOff : function()
349 {
350 Element.removeClassName(this,"selected");
351 this.autocomplete.selectedIndex = -1;
352 },
353
354 onItemClick : function()
355 {
356 this.autocomplete.selectedIndex = this.number;
357 this.autocomplete.select();
358 },
359
360 show : function()
361 {
362 if(this.matches.length <= 0)
363 return ;
364
365 var text = this.element.value;
366
367 // Modifications for multiples values
368 var exp = new RegExp(",?[^,]*$" , "i");
369 m = text.match(exp);
370 text = m[0].replace(/^[,\s]+|\s+$/g,"");
371
372 var expression = new RegExp("("+RegExp.escape(text)+")","i");
373
374 if(this.scroll > 0)
375 Element.removeClassName(this.upButton,"disabled")
376 else
377 Element.addClassName(this.upButton,"disabled")
378
379 if((this.scroll + this.MAX_VISIBLE) < this.matches.length)
380 Element.removeClassName(this.downButton,"disabled")
381 else
382 Element.addClassName(this.downButton,"disabled")
383
384 for(var i=0;i<this.MAX_VISIBLE;i++)
385 {
386 if(this.matches[i+this.scroll])
387 {
388 var text = this.matches[i+this.scroll];
389 text = text.replace(expression,"<strong>$1</strong>");
390 this.listItems[i].innerHTML = text;
391 this.listItems[i].number = i + this.scroll;
392 this.listItems[i].value = this.matches[i+this.scroll];
393
394 if(this.selectedIndex == (this.scroll + i))
395 Element.addClassName(this.listItems[i],"selected");
396 else
397 Element.removeClassName(this.listItems[i],"selected");
398
399 Element.show(this.listItems[i]);
400 }
401 else
402 {
403 Element.hide(this.listItems[i]);
404 }
405 }
406
407 this.visible = true;
408 Element.show(this.popup);
409 this.setPopupPosition();
410 },
411
412 setPopupPosition : function()
413 {
414 var position = Position.cumulativeOffset(this.element);
415 var scrollY = document.body.scrollTop ?
416 document.body.scrollTop : document.documentElement.scrollTop;
417 var viewHeight = (navigator.userAgent.toLowerCase().indexOf("safari") != -1 &&
418 window.innerHeight) ? window.innerHeight :
419 document.documentElement.clientHeight;
420
421 this.popup.style.width = (this.element.offsetWidth - 2) + "px";
422 this.popup.style.left = position[0] + "px";
423
424 var popupTop = position[1] + Element.getHeight(this.element);
425 if((popupTop + this.popup.offsetHeight > scrollY + viewHeight) &&
426 (position[1] - this.popup.offsetHeight > scrollY))
427 {
428 popupTop = position[1] - this.popup.offsetHeight;
429 }
430
431 this.popup.style.top = popupTop + "px";
432 },
433
434 hide : function()
435 {
436 this.matches = new Array();
437 this.selectedIndex = -1;
438 this.scroll = 0;
439 this.visible = false;
440 Element.hide(this.popup);
441 },
442
443 select : function()
444 {
445 if(this.selectedIndex != -1)
446 {
447 // Modifications for multiples values
448 //this.element.value += this.matches[this.selectedIndex]+', ';
449 this.element.value = this.element.value.replace(/(,?\s?)[^,]*$/i, "$1" + this.matches[this.selectedIndex] + ', ');
450 }
451 setCaretToEnd(this.element);
452 this.hide();
453 }
454};
455
456function setSelectionRange(input, selectionStart, selectionEnd) {
457 if (input.setSelectionRange) {
458 input.focus();
459 input.setSelectionRange(selectionStart, selectionEnd);
460 }
461 else if (input.createTextRange) {
462 var range = input.createTextRange();
463 range.collapse(true);
464 range.moveEnd('character', selectionEnd);
465 range.moveStart('character', selectionStart);
466 range.select();
467 }
468}
469
470function setCaretToEnd (input) {
471 setSelectionRange(input, input.value.length, input.value.length);
472}
Note: See TracBrowser for help on using the repository browser.