js tweak - use var for local variable; skip processing if not to be found
[mediawiki.git] / skins / common / mwsuggest.js
blob468dee1881c1b66eba164ca3dcf9a8f7142a9af9
1 /*
2  * OpenSearch ajax suggestion engine for MediaWiki
3  * 
4  * uses core MediaWiki open search support to fetch suggestions
5  * and show them below search boxes and other inputs
6  *
7  * by Robert Stojnic (April 2008)
8  */
9  
10 // search_box_id -> Results object 
11 var os_map = {};
12 // cached data, url -> json_text
13 var os_cache = {};
14 // global variables for suggest_keypress
15 var os_cur_keypressed = 0;
16 var os_last_keypress = 0;
17 var os_keypressed_count = 0;
18 // type: Timer
19 var os_timer = null;
20 // tie mousedown/up events
21 var os_mouse_pressed = false;
22 var os_mouse_num = -1;
23 // if true, the last change was made by mouse (and not keyboard)
24 var os_mouse_moved = false;
25 // delay between keypress and suggestion (in ms)
26 var os_search_timeout = 250;
27 // these pairs of inputs/forms will be autoloaded at startup
28 var os_autoload_inputs = new Array('searchInput', 'powerSearchText', 'searchText');
29 var os_autoload_forms = new Array('searchform', 'powersearch', 'search' );
30 // if we stopped the service
31 var os_is_stopped = false;
32 // max lines to show in suggest table
33 var os_max_lines_per_suggest = 7;
34 // if we are about to focus the searchbox for the first time
35 var os_first_focus = true;
37 /** Timeout timer class that will fetch the results */ 
38 function os_Timer(id,r,query){
39         this.id = id;
40         this.r = r;
41         this.query = query;     
44 /** Property class for single search box */
45 function os_Results(name, formname){    
46         this.searchform = formname; // id of the searchform
47         this.searchbox = name; // id of the searchbox
48         this.container = name+"Suggest"; // div that holds results
49         this.resultTable = name+"Result"; // id base for the result table (+num = table row)
50         this.resultText = name+"ResultText"; // id base for the spans within result tables (+num)
51         this.toggle = name+"Toggle"; // div that has the toggle (enable/disable) link
52         this.query = null; // last processed query
53         this.results = null;  // parsed titles
54         this.resultCount = 0; // number of results
55         this.original = null; // query that user entered 
56         this.selected = -1; // which result is selected
57         this.containerCount = 0; // number of results visible in container 
58         this.containerRow = 0; // height of result field in the container
59         this.containerTotal = 0; // total height of the container will all results
60         this.visible = false; // if container is visible
63 /** Hide results div */
64 function os_hideResults(r){
65         var c = document.getElementById(r.container);
66         if(c != null)
67                 c.style.visibility = "hidden";
68         r.visible = false;
69         r.selected = -1;
72 /** Show results div */
73 function os_showResults(r){
74         if(os_is_stopped)
75                 return;
76         os_fitContainer(r);
77         var c = document.getElementById(r.container);
78         r.selected = -1;
79         if(c != null){
80                 c.scrollTop = 0;
81                 c.style.visibility = "visible";
82                 r.visible = true;
83         }       
86 function os_operaWidthFix(x){
87         // TODO: better css2 incompatibility detection here
88         if(is_opera || is_khtml || navigator.userAgent.toLowerCase().indexOf('firefox/1')!=-1){
89                 return x - 30; // opera&konqueror & old firefox don't understand overflow-x, estimate scrollbar width
90         }       
91         return x;
94 function os_encodeQuery(value){
95   if (encodeURIComponent) {
96     return encodeURIComponent(value);
97   }
98   if(escape) {
99     return escape(value);
100   }
102 function os_decodeValue(value){
103   if (decodeURIComponent) {
104     return decodeURIComponent(value);
105   } 
106   if(unescape){
107         return unescape(value);
108   }
111 /** Brower-dependent functions to find window inner size, and scroll status */
112 function f_clientWidth() {
113         return f_filterResults (
114                 window.innerWidth ? window.innerWidth : 0,
115                 document.documentElement ? document.documentElement.clientWidth : 0,
116                 document.body ? document.body.clientWidth : 0
117         );
119 function f_clientHeight() {
120         return f_filterResults (
121                 window.innerHeight ? window.innerHeight : 0,
122                 document.documentElement ? document.documentElement.clientHeight : 0,
123                 document.body ? document.body.clientHeight : 0
124         );
126 function f_scrollLeft() {
127         return f_filterResults (
128                 window.pageXOffset ? window.pageXOffset : 0,
129                 document.documentElement ? document.documentElement.scrollLeft : 0,
130                 document.body ? document.body.scrollLeft : 0
131         );
133 function f_scrollTop() {
134         return f_filterResults (
135                 window.pageYOffset ? window.pageYOffset : 0,
136                 document.documentElement ? document.documentElement.scrollTop : 0,
137                 document.body ? document.body.scrollTop : 0
138         );
140 function f_filterResults(n_win, n_docel, n_body) {
141         var n_result = n_win ? n_win : 0;
142         if (n_docel && (!n_result || (n_result > n_docel)))
143                 n_result = n_docel;
144         return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
147 /** Get the height available for the results container */
148 function os_availableHeight(r){
149         var absTop = document.getElementById(r.container).style.top;
150         var px = absTop.lastIndexOf("px");
151         if(px > 0)
152                 absTop = absTop.substring(0,px);
153         return f_clientHeight() - (absTop - f_scrollTop());
157 /** Get element absolute position {left,top} */
158 function os_getElementPosition(elemID){
159         var offsetTrail = document.getElementById(elemID);
160         var offsetLeft = 0;
161         var offsetTop = 0;
162         while (offsetTrail){
163                 offsetLeft += offsetTrail.offsetLeft;
164                 offsetTop += offsetTrail.offsetTop;
165                 offsetTrail = offsetTrail.offsetParent;
166         }
167         if (navigator.userAgent.indexOf('Mac') != -1 && typeof document.body.leftMargin != 'undefined'){
168                 offsetLeft += document.body.leftMargin;
169                 offsetTop += document.body.topMargin;
170         }
171         return {left:offsetLeft,top:offsetTop};
174 /** Create the container div that will hold the suggested titles */
175 function os_createContainer(r){
176         var c = document.createElement("div");
177         var s = document.getElementById(r.searchbox);
178         var pos = os_getElementPosition(r.searchbox);   
179         var left = pos.left;
180         var top = pos.top + s.offsetHeight;
181         var body = document.getElementById("globalWrapper");
182         c.className = "os-suggest";
183         c.setAttribute("id", r.container);      
184         body.appendChild(c); 
185         
186         // dynamically generated style params   
187         // IE workaround, cannot explicitely set "style" attribute
188         c = document.getElementById(r.container);
189         c.style.top = top+"px";
190         c.style.left = left+"px";
191         c.style.width = s.offsetWidth+"px";
192         
193         // mouse event handlers
194         c.onmouseover = function(event) { os_eventMouseover(r.searchbox, event); };
195         c.onmousemove = function(event) { os_eventMousemove(r.searchbox, event); };
196         c.onmousedown = function(event) { return os_eventMousedown(r.searchbox, event); };
197         c.onmouseup = function(event) { os_eventMouseup(r.searchbox, event); };
198         return c;
201 /** change container height to fit to screen */
202 function os_fitContainer(r){    
203         var c = document.getElementById(r.container);
204         var h = os_availableHeight(r) - 20;
205         var inc = r.containerRow;
206         h = parseInt(h/inc) * inc;
207         if(h < (2 * inc) && r.resultCount > 1) // min: two results
208                 h = 2 * inc;    
209         if((h/inc) > os_max_lines_per_suggest )
210                 h = inc * os_max_lines_per_suggest;
211         if(h < r.containerTotal){
212                 c.style.height = h +"px";
213                 r.containerCount = parseInt(Math.round(h/inc));
214         } else{
215                 c.style.height = r.containerTotal+"px";
216                 r.containerCount = r.resultCount;
217         }
219 /** If some entries are longer than the box, replace text with "..." */
220 function os_trimResultText(r){
221         var w = document.getElementById(r.container).offsetWidth;
222         if(r.containerCount < r.resultCount){           
223                 w -= 20; // give 20px for scrollbar             
224         } else
225                 w = os_operaWidthFix(w);
226         if(w < 10)
227                 return;
228         for(var i=0;i<r.resultCount;i++){
229                 var e = document.getElementById(r.resultText+i);
230                 var replace = 1;
231                 var lastW = e.offsetWidth+1;
232                 var iteration = 0;
233                 var changedText = false;
234                 while(e.offsetWidth > w && (e.offsetWidth < lastW || iteration<2)){
235                         changedText = true;
236                         lastW = e.offsetWidth;
237                         var l = e.innerHTML;                    
238                         e.innerHTML = l.substring(0,l.length-replace)+"...";
239                         iteration++;
240                         replace = 4; // how many chars to replace
241                 }
242                 if(changedText){
243                         // show hint for trimmed titles
244                         document.getElementById(r.resultTable+i).setAttribute("title",r.results[i]);
245                 }
246         }
249 /** Handles data from XMLHttpRequest, and updates the suggest results */
250 function os_updateResults(r, query, text, cacheKey){     
251         os_cache[cacheKey] = text;
252         r.query = query;
253         r.original = query;
254         if(text == ""){
255                 r.results = null;
256                 r.resultCount = 0;
257                 os_hideResults(r);
258         } else{         
259                 try {
260                         var p = eval('('+text+')'); // simple json parse, could do a safer one
261                         if(p.length<2 || p[1].length == 0){
262                                 r.results = null;
263                                 r.resultCount = 0;
264                                 os_hideResults(r);
265                                 return;
266                         }               
267                         var c = document.getElementById(r.container);
268                         if(c == null)
269                                 c = os_createContainer(r);                      
270                         c.innerHTML = os_createResultTable(r,p[1]);
271                         // init container table sizes
272                         var t = document.getElementById(r.resultTable);         
273                         r.containerTotal = t.offsetHeight;      
274                         r.containerRow = t.offsetHeight / r.resultCount;
275                         os_trimResultText(r);                           
276                         os_showResults(r);
277                 } catch(e){
278                         // bad response from server or such
279                         os_hideResults(r);                      
280                         os_cache[cacheKey] = null;
281                 }
282         }       
285 /** Create the result table to be placed in the container div */
286 function os_createResultTable(r, results){
287         var c = document.getElementById(r.container);
288         var width = os_operaWidthFix(c.offsetWidth);    
289         var html = "<table class=\"os-suggest-results\" id=\""+r.resultTable+"\" style=\"width: "+width+"px;\">";
290         r.results = new Array();
291         r.resultCount = results.length;
292         for(i=0;i<results.length;i++){
293                 var title = os_decodeValue(results[i]);
294                 r.results[i] = title;
295                 html += "<tr><td class=\"os-suggest-result\" id=\""+r.resultTable+i+"\"><span id=\""+r.resultText+i+"\">"+title+"</span></td></tr>";
296         }
297         html+="</table>"
298         return html;
301 /** Fetch namespaces from checkboxes or hidden fields in the search form,
302     if none defined use wgSearchNamespaces global */
303 function os_getNamespaces(r){   
304         var namespaces = "";
305         var elements = document.forms[r.searchform].elements;
306         for(i=0; i < elements.length; i++){
307                 var name = elements[i].name;
308                 if(typeof name != 'undefined' && name.length > 2 
309                 && name[0]=='n' && name[1]=='s' 
310                 && ((elements[i].type=='checkbox' && elements[i].checked) 
311                         || (elements[i].type=='hidden' && elements[i].value=="1")) ){
312                         if(namespaces!="")
313                                 namespaces+="|";
314                         namespaces+=name.substring(2);
315                 }
316         }
317         if(namespaces == "")
318                 namespaces = wgSearchNamespaces.join("|");
319         return namespaces;
322 /** Update results if user hasn't already typed something else */
323 function os_updateIfRelevant(r, query, text, cacheKey){
324         var t = document.getElementById(r.searchbox);
325         if(t != null && t.value == query){ // check if response is still relevant                                       
326                 os_updateResults(r, query, text, cacheKey);
327         }
328         r.query = query;
331 /** Fetch results after some timeout */
332 function os_delayedFetch(){
333         if(os_timer == null)
334                 return;
335         var r = os_timer.r;
336         var query = os_timer.query;
337         os_timer = null;
338         var path = wgMWSuggestTemplate.replace("{namespaces}",os_getNamespaces(r))
339                                                                   .replace("{dbname}",wgDBname)
340                                                                   .replace("{searchTerms}",os_encodeQuery(query));
341         
342         // try to get from cache, if not fetch using ajax
343         var cached = os_cache[path];
344         if(cached != null){
345                 os_updateIfRelevant(r, query, cached, path);
346         } else{                                                                   
347                 var xmlhttp = sajax_init_object();
348                 if(xmlhttp){
349                         try {                   
350                                 xmlhttp.open("GET", path, true);
351                                 xmlhttp.onreadystatechange=function(){
352                                 if (xmlhttp.readyState==4 && typeof os_updateIfRelevant == 'function') {                                
353                                         os_updateIfRelevant(r, query, xmlhttp.responseText, path);
354                                 }
355                         };
356                         xmlhttp.send(null);             
357                 } catch (e) {
358                                 if (window.location.hostname == "localhost") {
359                                         alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing.");
360                                 }
361                                 throw e;
362                         }
363                 }
364         }
367 /** Init timed update via os_delayedUpdate() */
368 function os_fetchResults(r, query, timeout){
369         if(query == ""){
370                 os_hideResults(r);
371                 return;
372         } else if(query == r.query)
373                 return; // no change
374         
375         os_is_stopped = false; // make sure we're running
376         
377         /* var cacheKey = wgDBname+":"+query; 
378         var cached = os_cache[cacheKey];
379         if(cached != null){
380                 os_updateResults(r,wgDBname,query,cached);
381                 return;
382         } */
383         
384         // cancel any pending fetches
385         if(os_timer != null && os_timer.id != null)
386                 clearTimeout(os_timer.id);
387         // schedule delayed fetching of results 
388         if(timeout != 0){
389                 os_timer = new os_Timer(setTimeout("os_delayedFetch()",timeout),r,query);
390         } else{         
391                 os_timer = new os_Timer(null,r,query);
392                 os_delayedFetch(); // do it now!
393         }
396 /** Change the highlighted row (i.e. suggestion), from position cur to next */
397 function os_changeHighlight(r, cur, next, updateSearchBox){
398         if (next >= r.resultCount)
399                 next = r.resultCount-1;
400         if (next < -1)
401                 next = -1;   
402         r.selected = next;
403         if (cur == next)
404         return; // nothing to do.
405     
406     if(cur >= 0){
407         var curRow = document.getElementById(r.resultTable + cur);
408         if(curRow != null)
409                 curRow.className = "os-suggest-result";
410     }
411     var newText;
412     if(next >= 0){
413         var nextRow = document.getElementById(r.resultTable + next);
414         if(nextRow != null)
415                 nextRow.className = "os-suggest-result-hl";
416         newText = r.results[next];
417     } else
418         newText = r.original;
419         
420     // adjust the scrollbar if any
421     if(r.containerCount < r.resultCount){
422         var c = document.getElementById(r.container);
423         var vStart = c.scrollTop / r.containerRow;
424         var vEnd = vStart + r.containerCount;
425         if(next < vStart)
426                 c.scrollTop = next * r.containerRow;
427         else if(next >= vEnd)
428                 c.scrollTop = (next - r.containerCount + 1) * r.containerRow;
429     }
430         
431     // update the contents of the search box
432     if(updateSearchBox){
433         os_updateSearchQuery(r,newText);        
434     }
437 function os_updateSearchQuery(r,newText){
438         document.getElementById(r.searchbox).value = newText;
439     r.query = newText;
442 /** Find event target */
443 function os_getTarget(e){
444         if (!e) var e = window.event;
445         if (e.target) return e.target;
446         else if (e.srcElement) return e.srcElement;
447         else return null;
452 /********************
453  *  Keyboard events 
454  ********************/ 
456 /** Event handler that will fetch results on keyup */
457 function os_eventKeyup(e){
458         var targ = os_getTarget(e);
459         var r = os_map[targ.id];
460         if(r == null)
461                 return; // not our event
462                 
463         // some browsers won't generate keypressed for arrow keys, catch it 
464         if(os_keypressed_count == 0){
465                 os_processKey(r,os_cur_keypressed,targ);
466         }
467         var query = targ.value;
468         os_fetchResults(r,query,os_search_timeout);
471 /** catch arrows up/down and escape to hide the suggestions */
472 function os_processKey(r,keypressed,targ){
473         if (keypressed == 40){ // Arrow Down
474         if (r.visible) {                
475                 os_changeHighlight(r, r.selected, r.selected+1, true);                  
476         } else if(os_timer == null){
477                 // user wants to get suggestions now
478                 r.query = "";
479                         os_fetchResults(r,targ.value,0);
480         }
481         } else if (keypressed == 38){ // Arrow Up
482                 if (r.visible){
483                         os_changeHighlight(r, r.selected, r.selected-1, true);
484                 }
485         } else if(keypressed == 27){ // Escape
486                 document.getElementById(r.searchbox).value = r.original;
487                 r.query = r.original;
488                 os_hideResults(r);
489         } else if(r.query != document.getElementById(r.searchbox).value){
490                 // os_hideResults(r); // don't show old suggestions
491         }
494 /** When keys is held down use a timer to output regular events */
495 function os_eventKeypress(e){   
496         var targ = os_getTarget(e);
497         var r = os_map[targ.id];
498         if(r == null)
499                 return; // not our event
500         
501         var keypressed = os_cur_keypressed;
502         if(keypressed == 38 || keypressed == 40){
503                 var d = new Date()
504                 var now = d.getTime();
505                 if(now - os_last_keypress < 120){
506                         os_last_keypress = now;
507                         return;
508                 }
509         }
510         
511         os_keypressed_count++;
512         os_processKey(r,keypressed,targ);
515 /** Catch the key code (Firefox bug)  */
516 function os_eventKeydown(e){
517         if (!e) var e = window.event;
518         if (e.target) var targ = e.target;
519         else if (e.srcElement) var targ = e.srcElement;
520         else return;
521         var r = os_map[targ.id];
522         if(r == null)
523                 return; // not our event
524                         
525         os_mouse_moved = false;
526                 
527         if(os_first_focus){
528                 // firefox bug, focus&defocus to make autocomplete=off valid
529                 targ.blur(); targ.focus();
530                 os_first_focus = false;
531         }
533         os_cur_keypressed = (window.Event) ? e.which : e.keyCode;
534         os_last_keypress = 0;
535         os_keypressed_count = 0;
538 /** Event: loss of focus of input box */
539 function os_eventBlur(e){       
540         if(os_first_focus)
541                 return; // we are focusing/defocusing
542         var targ = os_getTarget(e);
543         var r = os_map[targ.id];
544         if(r == null)
545                 return; // not our event
546         if(!os_mouse_pressed)   
547                 os_hideResults(r);
550 /** Event: focus (catch only when stopped) */
551 function os_eventFocus(e){      
552         if(os_first_focus)
553                 return; // we are focusing/defocusing
558 /********************
559  *  Mouse events 
560  ********************/ 
562 /** Mouse over the container */
563 function os_eventMouseover(srcId, e){
564         var targ = os_getTarget(e);     
565         var r = os_map[srcId];
566         if(r == null || !os_mouse_moved)
567                 return; // not our event
568         var num = os_getNumberSuffix(targ.id);
569         if(num >= 0)
570                 os_changeHighlight(r,r.selected,num,false);
571                                         
574 /* Get row where the event occured (from its id) */
575 function os_getNumberSuffix(id){
576         var num = id.substring(id.length-2);
577         if( ! (num.charAt(0) >= '0' && num.charAt(0) <= '9') )
578                 num = num.substring(1);
579         if(os_isNumber(num))
580                 return parseInt(num);
581         else
582                 return -1;
585 /** Save mouse move as last action */
586 function os_eventMousemove(srcId, e){
587         os_mouse_moved = true;
590 /** Mouse button held down, register possible click  */
591 function os_eventMousedown(srcId, e){
592         var targ = os_getTarget(e);
593         var r = os_map[srcId];
594         if(r == null)
595                 return; // not our event
596         var num = os_getNumberSuffix(targ.id);
597         
598         os_mouse_pressed = true;
599         if(num >= 0){
600                 os_mouse_num = num;
601                 // os_updateSearchQuery(r,r.results[num]);
602         }
603         // keep the focus on the search field
604         document.getElementById(r.searchbox).focus();
605         
606         return false; // prevents selection
609 /** Mouse button released, check for click on some row */
610 function os_eventMouseup(srcId, e){
611         var targ = os_getTarget(e);
612         var r = os_map[srcId];
613         if(r == null)
614                 return; // not our event
615         var num = os_getNumberSuffix(targ.id);
616                 
617         if(num >= 0 && os_mouse_num == num){
618                 os_updateSearchQuery(r,r.results[num]);
619                 os_hideResults(r);
620                 document.getElementById(r.searchform).submit();
621         }
622         os_mouse_pressed = false;
623         // keep the focus on the search field
624         document.getElementById(r.searchbox).focus();
627 /** Check if x is a valid integer */
628 function os_isNumber(x){
629         if(x == "" || isNaN(x))
630                 return false;
631         for(var i=0;i<x.length;i++){
632                 var c = x.charAt(i);
633                 if( ! (c >= '0' && c <= '9') )
634                         return false;
635         }
636         return true;
640 /** When the form is submitted hide everything, cancel updates... */
641 function os_eventOnsubmit(e){
642         var targ = os_getTarget(e);
644         os_is_stopped = true;
645         // kill timed requests
646         if(os_timer != null && os_timer.id != null){
647                 clearTimeout(os_timer.id);
648                 os_timer = null;
649         }
650         // Hide all suggestions
651         for(i=0;i<os_autoload_inputs.length;i++){
652                 var r = os_map[os_autoload_inputs[i]];
653                 if(r != null){
654                         var b = document.getElementById(r.searchform);
655                         if(b != null && b == targ){ 
656                                 // set query value so the handler won't try to fetch additional results
657                                 r.query = document.getElementById(r.searchbox).value;
658                         }                       
659                         os_hideResults(r);
660                 }
661         }
662         return true;
665 /** Init Result objects and event handlers */
666 function os_initHandlers(name, formname, element){
667         var r = new os_Results(name, formname); 
668         // event handler
669         element.onkeyup = function(event) { os_eventKeyup(event); };
670         element.onkeydown = function(event) { os_eventKeydown(event); };
671         element.onkeypress = function(event) { os_eventKeypress(event); };
672         element.onblur = function(event) { os_eventBlur(event); };
673         element.onfocus = function(event) { os_eventFocus(event); };
674         element.setAttribute("autocomplete","off");
675         // stopping handler
676         document.getElementById(formname).onsubmit = function(event){ return os_eventOnsubmit(event); };
677         os_map[name] = r; 
678         // toggle link
679         if(document.getElementById(r.toggle) == null){
680                 // TODO: disable this while we figure out a way for this to work in all browsers 
681                 /* if(name=='searchInput'){
682                         // special case: place above the main search box
683                         var t = os_createToggle(r,"os-suggest-toggle");
684                         var searchBody = document.getElementById('searchBody');
685                         var first = searchBody.parentNode.firstChild.nextSibling.appendChild(t);
686                 } else{
687                         // default: place below search box to the right
688                         var t = os_createToggle(r,"os-suggest-toggle-def");
689                         var top = element.offsetTop + element.offsetHeight;
690                         var left = element.offsetLeft + element.offsetWidth;
691                         t.style.position = "absolute";
692                         t.style.top = top + "px";
693                         t.style.left = left + "px";
694                         element.parentNode.appendChild(t);
695                         // only now width gets calculated, shift right
696                         left -= t.offsetWidth;
697                         t.style.left = left + "px";
698                         t.style.visibility = "visible";
699                 } */
700         }
701         
704 /** Return the span element that contains the toggle link */
705 function os_createToggle(r,className){
706         var t = document.createElement("span");
707         t.className = className;
708         t.setAttribute("id", r.toggle);
709         var link = document.createElement("a");
710         link.setAttribute("href","javascript:void(0);");
711         link.onclick = function(){ os_toggle(r.searchbox,r.searchform) };
712         var msg = document.createTextNode(wgMWSuggestMessages[0]);
713         link.appendChild(msg);
714         t.appendChild(link);
715         return t;       
718 /** Call when user clicks on some of the toggle links */
719 function os_toggle(inputId,formName){
720         r = os_map[inputId];
721         var msg = '';
722         if(r == null){
723                 os_enableSuggestionsOn(inputId,formName);
724                 r = os_map[inputId];
725                 msg = wgMWSuggestMessages[0];           
726         } else{
727                 os_disableSuggestionsOn(inputId,formName);
728                 msg = wgMWSuggestMessages[1];
729         }
730         // change message
731         var link = document.getElementById(r.toggle).firstChild;
732         link.replaceChild(document.createTextNode(msg),link.firstChild);
735 /** Call this to enable suggestions on input (id=inputId), on a form (name=formName) */
736 function os_enableSuggestionsOn(inputId, formName){
737         os_initHandlers( inputId, formName, document.getElementById(inputId) );
740 /** Call this to disable suggestios on input box (id=inputId) */
741 function os_disableSuggestionsOn(inputId){
742         r = os_map[inputId];
743         if(r != null){
744                 // cancel/hide results
745                 os_timer = null;
746                 os_hideResults(r);
747                 // turn autocomplete on !
748                 document.getElementById(inputId).setAttribute("autocomplete","on");
749                 // remove descriptor    
750                 os_map[inputId] = null;
751         }
754 /** Initialization, call upon page onload */
755 function os_MWSuggestInit() {
756         for(i=0;i<os_autoload_inputs.length;i++){
757                 var id = os_autoload_inputs[i];
758                 var form = os_autoload_forms[i];
759                 element = document.getElementById( id );
760                 if(element != null)
761                         os_initHandlers(id,form,element);
762         }       
765 hookEvent("load", os_MWSuggestInit);