includes/clientside/static/autofill.js
changeset 581 5e8fd89c02ea
parent 550 685e839d934e
child 582 a38876c0793c
equal deleted inserted replaced
580:41c45314ac27 581:5e8fd89c02ea
     1 /**
     1 /**
     2  * Javascript auto-completion for form fields. This supercedes the code in autocomplete.js for MOZILLA ONLY. It doesn't seem to work real
     2  * Javascript auto-completion for form fields. This supercedes the code in autocomplete.js for MOZILLA ONLY. It doesn't seem to work real
     3  * well with other browsers yet.
     3  * well with other browsers yet.
     4  */
     4  */
     5  
     5 
     6 var af_current = false;
     6 // fill schemas
     7  
     7 var autofill_schemas = {};
     8 function AutofillUsername(parent, event, allowanon)
     8 
       
     9 // default, generic schema
       
    10 autofill_schemas.generic = {
       
    11   template: '<div id="--ID--_region" spry:region="autofill_region_--ID--" class="tblholder">' + "\n" +
       
    12             '  <table border="0" cellspacing="1" cellpadding="3" style="font-size: smaller;">' + "\n" +
       
    13             '    <tr spry:repeat="autofill_region_--ID--">' + "\n" +
       
    14             '      <td class="row1" spry:suggest="{name}">{name}</td>' + "\n" +
       
    15             '    </tr>' + "\n" +
       
    16             '  </table>' + "\n" +
       
    17             '</div>',
       
    18   
       
    19   init: function(element, fillclass)
       
    20   {
       
    21     // setup the dataset
       
    22     window["autofill_region_" + element.id] = new Spry.Data.JSONDataSet(makeUrlNS('Special', 'Autofill', 'type=' + fillclass));
       
    23     
       
    24     // inject our HTML wrapper
       
    25     var template = this.template.replace(new RegExp('--ID--', 'g'), element.id);
       
    26     var wrapper = element.parentNode; // document.createElement('div');
       
    27     wrapper.id = 'autofill_wrap_' + element.id;
       
    28     
       
    29     // a bunch of hacks to add a spry wrapper
       
    30     // var el2 = element.cloneNode(false);
       
    31     // wrapper.appendChild(el2);
       
    32     wrapper.innerHTML += template;
       
    33     // insertAfter(element.parentNode, wrapper, element);
       
    34     // element.parentNode.removeChild(element);
       
    35     // element = el2;
       
    36     
       
    37     var autosuggest = new Spry.Widget.AutoSuggest("autofill_wrap_" + element.id, element.id + '_region', window["autofill_region_" + element.id], 'name', {loadFromServer: true, urlParam: 'userinput', hoverSuggestClass: 'row2', minCharsType: 3});
       
    38   }
       
    39 };
       
    40 
       
    41 function autofill_init_element(element, params)
     9 {
    42 {
    10   // if this is IE, use the old code
    43   if ( element.parentNode.id.match(/^autofill_wrap_/) )
    11   if ( IE )
    44     return false;
       
    45   
       
    46   params = params || {};
       
    47   // assign an ID if it doesn't have one yet
       
    48   if ( !element.id )
    12   {
    49   {
    13     ajaxUserNameComplete(parent);
    50     element.id = 'autofill_' + Math.floor(Math.random() * 100000);
    14     return false;
       
    15   }
    51   }
    16   if ( parent.afobj )
    52   var id = element.id;
       
    53   
       
    54   // get the fill type
       
    55   var fillclass = element.className;
       
    56   fillclass = fillclass.split(' ');
       
    57   fillclass = fillclass[1];
       
    58   
       
    59   var schema = ( autofill_schemas[fillclass] ) ? autofill_schemas[fillclass] : autofill_schemas['generic'];
       
    60   if ( typeof(schema.init) != 'function' )
    17   {
    61   {
    18     parent.afobj.go();
    62     schema.init = autofill_schemas.generic.init;
    19     return true;
    63   }
       
    64   schema.init(element, fillclass, params);
       
    65   
       
    66   element.af_initted = true;
       
    67 }
       
    68 
       
    69 var autofill_onload = function()
       
    70 {
       
    71   autofill_schemas.username = {
       
    72     template: '<div id="--ID--_region" spry:region="autofill_region_--ID--" class="tblholder">' + "\n" +
       
    73               '  <table border="0" cellspacing="1" cellpadding="3" style="font-size: smaller;">' + "\n" +
       
    74               '    <tr>' + "\n" +
       
    75               '      <th>' + $lang.get('user_autofill_heading_suggestions') + '</th>' + "\n" +
       
    76               '    </tr>' + "\n" +
       
    77               '    <tr spry:repeat="autofill_region_--ID--">' + "\n" +
       
    78               '      <td class="row1" spry:suggest="{name}">{name_highlight}<br /><small style="{rank_style}">{rank_title}</small></td>' + "\n" +
       
    79               '    </tr>' + "\n" +
       
    80               '  </table>' + "\n" +
       
    81               '</div>',
       
    82     
       
    83     init: function(element, fillclass, params)
       
    84     {
       
    85       // calculate positions before spry f***s everything up
       
    86       var top = $dynano(element).Top() + $dynano(element).Height() - 10; // tblholder has 10px top margin
       
    87       var left = $dynano(element).Left();
       
    88       
       
    89       var allow_anon = ( params.allow_anon ) ? '1' : '0';
       
    90       // setup the dataset
       
    91       window["autofill_region_" + element.id] = new Spry.Data.JSONDataSet(makeUrlNS('Special', 'Autofill', 'type=' + fillclass + '&allow_anon' + allow_anon));
       
    92       Spry.Data.initRegions(document.body);
       
    93       (window["autofill_region_" + element.id]).loadData();
       
    94       
       
    95       // inject our HTML wrapper
       
    96       var template = this.template.replace(new RegExp('--ID--', 'g'), element.id);
       
    97       var wrapper = element.parentNode; // document.createElement('div');
       
    98       wrapper.id = 'autofill_wrap_' + element.id;
       
    99       
       
   100       // a bunch of hacks to add a spry wrapper
       
   101       wrapper.innerHTML = template + wrapper.innerHTML;
       
   102       
       
   103       var autosuggest = new Spry.Widget.AutoSuggest("autofill_wrap_" + element.id, element.id + '_region', window["autofill_region_" + element.id], 'name', {loadFromServer: true, urlParam: 'userinput', hoverSuggestClass: 'row2', minCharsType: 3});
       
   104       var regiondiv = document.getElementById(element.id + '_region');
       
   105       regiondiv.style.position = 'absolute';
       
   106       regiondiv.style.top = top + 'px';
       
   107       regiondiv.style.left = left + 'px';
       
   108     }
       
   109   };
       
   110   
       
   111   autofill_schemas.page = {
       
   112     template: '<div id="--ID--_region" spry:region="autofill_region_--ID--" class="tblholder">' + "\n" +
       
   113               '  <table border="0" cellspacing="1" cellpadding="3" style="font-size: smaller;">' + "\n" +
       
   114               '    <tr>' + "\n" +
       
   115               '      <th colspan="2">' + $lang.get('page_autosuggest_heading') + '</th>' + "\n" +
       
   116               '    </tr>' + "\n" +
       
   117               '    <tr spry:repeat="autofill_region_--ID--">' + "\n" +
       
   118               '      <td class="row1" spry:suggest="{page_id}">{pid_highlight}<br /><small>{name_highlight}</small></td>' + "\n" +
       
   119               '    </tr>' + "\n" +
       
   120               '  </table>' + "\n" +
       
   121               '</div>'
    20   }
   122   }
    21   
   123   
    22   parent.autocomplete = 'off';
   124   var inputs = document.getElementsByClassName('input', 'autofill');
    23   parent.setAttribute('autocomplete', 'off');
       
    24   
   125   
    25   this.repeat = false;
   126   for ( var i = 0; i < inputs.length; i++ )
    26   this.event = event;
   127   {
    27   this.box_id = false;
   128     autofill_init_element(inputs[i]);
    28   this.boxes = new Array();
   129   }
    29   this.state = false;
   130 }
    30   this.allowanon = ( allowanon ) ? true : false;
   131 
       
   132 addOnloadHook(autofill_onload);
       
   133 
       
   134 function AutofillUsername(element, event, allowanon)
       
   135 {
       
   136   element.onkeyup = element.onkeydown = element.onkeypress = function(e) {};
    31   
   137   
    32   if ( !parent.id )
   138   element.className = 'autofill username';
    33     parent.id = 'afuser_' + Math.floor(Math.random() * 1000000);
       
    34   
   139   
    35   this.field_id = parent.id;
   140   allowanon = allowanon ? true : false;
    36   
   141   autofill_init_element(element, {
    37   // constants
   142       allow_anon: allowanon
    38   this.KEY_UP    = 38;
   143     });
    39   this.KEY_DOWN  = 40;
       
    40   this.KEY_ESC   = 27;
       
    41   this.KEY_TAB   = 9;
       
    42   this.KEY_ENTER = 13;
       
    43   
       
    44   // response cache
       
    45   this.responses = new Object();
       
    46   
       
    47   // ajax placeholder
       
    48   this.process_dataset = function(resp_json)
       
    49   {
       
    50     // window.console.info('Processing the following dataset.');
       
    51     // window.console.debug(resp_json);
       
    52     var autofill = this;
       
    53     
       
    54     if ( typeof(autofill.event) == 'object' )
       
    55     {
       
    56       if ( autofill.event.keyCode )
       
    57       {
       
    58         if ( autofill.event.keyCode == autofill.KEY_ENTER && autofill.boxes.length < 1 && !autofill.box_id )
       
    59         {
       
    60           // user hit enter after accepting a suggestion - submit the form
       
    61           var frm = findParentForm($dynano(autofill.field_id).object);
       
    62           frm._af_acting = false;
       
    63           frm.submit();
       
    64           // window.console.info('Submitting form');
       
    65           return false;
       
    66         }
       
    67         if ( autofill.event.keyCode == autofill.KEY_UP || autofill.event.keyCode == autofill.KEY_DOWN || autofill.event.keyCode == autofill.KEY_ESC || autofill.event.keyCode == autofill.KEY_TAB || autofill.event.keyCode == autofill.KEY_ENTER )
       
    68         {
       
    69           autofill.keyhandler();
       
    70           // window.console.info('Control key detected, called keyhandler and exiting');
       
    71           return true;
       
    72         }
       
    73       }
       
    74     }
       
    75     
       
    76     if ( this.box_id )
       
    77     {
       
    78       this.destroy();
       
    79       // window.console.info('already have a box open - destroying and exiting');
       
    80       //return false;
       
    81     }
       
    82     
       
    83     var users = new Array();
       
    84     for ( var i = 0; i < resp_json.users_real.length; i++ )
       
    85     {
       
    86       try
       
    87       {
       
    88         var user = resp_json.users_real[i].toLowerCase();
       
    89         var inp  = $dynano(autofill.field_id).object.value;
       
    90         inp = inp.toLowerCase();
       
    91         if ( user.indexOf(inp) > -1 )
       
    92         {
       
    93           users.push(resp_json.users_real[i]);
       
    94         }
       
    95       }
       
    96       catch(e)
       
    97       {
       
    98         users.push(resp_json.users_real[i]);
       
    99       }
       
   100     }
       
   101 
       
   102     // This was used ONLY for debugging the DOM and list logic    
       
   103     // resp_json.users = resp_json.users_real;
       
   104     
       
   105     // construct table
       
   106     var div = document.createElement('div');
       
   107     div.className = 'tblholder';
       
   108     div.style.clip = 'rect(0px,auto,auto,0px)';
       
   109     div.style.maxHeight = '200px';
       
   110     div.style.overflow = 'auto';
       
   111     div.style.zIndex = '9999';
       
   112     var table = document.createElement('table');
       
   113     table.border = '0';
       
   114     table.cellSpacing = '1';
       
   115     table.cellPadding = '3';
       
   116     
       
   117     var tr = document.createElement('tr');
       
   118     var th = document.createElement('th');
       
   119     th.appendChild(document.createTextNode($lang.get('user_autofill_heading_suggestions')));
       
   120     tr.appendChild(th);
       
   121     table.appendChild(tr);
       
   122     
       
   123     if ( users.length < 1 )
       
   124     {
       
   125       var tr = document.createElement('tr');
       
   126       var td = document.createElement('td');
       
   127       td.className = 'row1';
       
   128       td.appendChild(document.createTextNode($lang.get('user_autofill_msg_no_suggestions')));
       
   129       td.afobj = autofill;
       
   130       tr.appendChild(td);
       
   131       table.appendChild(tr);
       
   132     }
       
   133     else
       
   134       
       
   135       for ( var i = 0; i < users.length; i++ )
       
   136       {
       
   137         var user = users[i];
       
   138         var tr = document.createElement('tr');
       
   139         var td = document.createElement('td');
       
   140         td.className = ( i == 0 ) ? 'row2' : 'row1';
       
   141         td.appendChild(document.createTextNode(user));
       
   142         td.afobj = autofill;
       
   143         td.style.cursor = 'pointer';
       
   144         td.onclick = function()
       
   145         {
       
   146           this.afobj.set(this.firstChild.nodeValue);
       
   147         }
       
   148         tr.appendChild(td);
       
   149         table.appendChild(tr);
       
   150       }
       
   151       
       
   152     // Finalize div
       
   153     var tb_top    = $dynano(autofill.field_id).Top();
       
   154     var tb_height = $dynano(autofill.field_id).Height();
       
   155     var af_top    = tb_top + tb_height - 9;
       
   156     var tb_left   = $dynano(autofill.field_id).Left();
       
   157     var af_left   = tb_left;
       
   158     
       
   159     div.style.position = 'absolute';
       
   160     div.style.left = af_left + 'px';
       
   161     div.style.top  = af_top  + 'px';
       
   162     div.style.width = '200px';
       
   163     div.style.fontSize = '7pt';
       
   164     div.style.fontFamily = 'Trebuchet MS, arial, helvetica, sans-serif';
       
   165     div.id = 'afuserdrop_' + Math.floor(Math.random() * 1000000);
       
   166     div.appendChild(table);
       
   167     
       
   168     autofill.boxes.push(div.id);
       
   169     autofill.box_id = div.id;
       
   170     if ( users.length > 0 )
       
   171       autofill.state = users[0];
       
   172     
       
   173     var body = document.getElementsByTagName('body')[0];
       
   174     body.appendChild(div);
       
   175     
       
   176     autofill.repeat = true;
       
   177   }
       
   178   
       
   179   // perform ajax call
       
   180   this.fetch_and_process = function()
       
   181   {
       
   182     af_current = this;
       
   183     var processResponse = function()
       
   184     {
       
   185       if ( ajax.readyState == 4 && ajax.status == 200 )
       
   186       {
       
   187         var afobj = af_current;
       
   188         af_current = false;
       
   189         // parse the JSON response
       
   190         var response = String(ajax.responseText) + ' ';
       
   191         if ( response.substr(0,1) != '{' )
       
   192         {
       
   193           new MessageBox(MB_OK|MB_ICONSTOP, 'Invalid response', 'Invalid or unexpected JSON response from server:<pre>' + ajax.responseText + '</pre>');
       
   194           return false;
       
   195         }
       
   196         if ( $dynano(afobj.field_id).object.value.length < 3 )
       
   197           return false;
       
   198         var resp_json = parseJSON(response);
       
   199         var resp_code = $dynano(afobj.field_id).object.value.toLowerCase().substr(0, 3);
       
   200         afobj.responses[resp_code] = resp_json;
       
   201         afobj.process_dataset(resp_json);
       
   202       }
       
   203     }
       
   204     var usernamefragment = ajaxEscape($dynano(this.field_id).object.value);
       
   205     ajaxGet(stdAjaxPrefix + '&_mode=fillusername&name=' + usernamefragment + '&allowanon=' + ( this.allowanon ? '1' : '0' ), processResponse);
       
   206   }
       
   207   
       
   208   this.go = function()
       
   209   {
       
   210     if ( document.getElementById(this.field_id).value.length < 3 )
       
   211     {
       
   212       this.destroy();
       
   213       return false;
       
   214     }
       
   215     
       
   216     if ( af_current )
       
   217       return false;
       
   218     
       
   219     var resp_code = $dynano(this.field_id).object.value.toLowerCase().substr(0, 3);
       
   220     if ( this.responses.length < 1 || ! this.responses[ resp_code ] )
       
   221     {
       
   222       // window.console.info('Cannot find dataset ' + resp_code + ' in cache, sending AJAX request');
       
   223       this.fetch_and_process();
       
   224     }
       
   225     else
       
   226     {
       
   227       // window.console.info('Using cached dataset: ' + resp_code);
       
   228       var resp_json = this.responses[ resp_code ];
       
   229       this.process_dataset(resp_json);
       
   230     }
       
   231     document.getElementById(this.field_id).onkeyup = function(event)
       
   232     {
       
   233       this.afobj.event = event;
       
   234       this.afobj.go();
       
   235     }
       
   236     document.getElementById(this.field_id).onkeydown = function(event)
       
   237     {
       
   238       var form = findParentForm(this);
       
   239       if ( typeof(event) != 'object' )
       
   240         var event = window.event;
       
   241       if ( typeof(event) == 'object' )
       
   242       {
       
   243         if ( event.keyCode == this.afobj.KEY_ENTER && this.afobj.boxes.length < 1 && !this.afobj.box_id )
       
   244         {
       
   245           // user hit enter after accepting a suggestion - submit the form
       
   246           form._af_acting = false;
       
   247           return true;
       
   248         }
       
   249         else
       
   250         {
       
   251           form._af_acting = true;
       
   252           return true;
       
   253         }
       
   254       }
       
   255     }
       
   256   }
       
   257   
       
   258   this.keyhandler = function()
       
   259   {
       
   260     var key = this.event.keyCode;
       
   261     if ( key == this.KEY_ENTER && !this.repeat )
       
   262     {
       
   263       submitAuthorized = true;
       
   264       var form = findParentForm($dynano(this.field_id).object);
       
   265       form._af_acting = false;
       
   266       return true;
       
   267     }
       
   268     switch(key)
       
   269     {
       
   270       case this.KEY_UP:
       
   271         this.focus_up();
       
   272         break;
       
   273       case this.KEY_DOWN:
       
   274         this.focus_down();
       
   275         break;
       
   276       case this.KEY_ESC:
       
   277         this.destroy();
       
   278         break;
       
   279       case this.KEY_TAB:
       
   280         this.destroy();
       
   281         break;
       
   282       case this.KEY_ENTER:
       
   283         this.set();
       
   284         break;
       
   285     }
       
   286     
       
   287     var form = findParentForm($dynano(this.field_id).object);
       
   288       form._af_acting = false;
       
   289   }
       
   290   
       
   291   this.get_state_td = function()
       
   292   {
       
   293     var div = document.getElementById(this.box_id);
       
   294     if ( !div )
       
   295       return false;
       
   296     if ( !this.state )
       
   297       return false;
       
   298     var table = div.firstChild;
       
   299     for ( var i = 1; i < table.childNodes.length; i++ )
       
   300     {
       
   301       // the table is DOM-constructed so no cruddy HTML hacks :-)
       
   302       var child = table.childNodes[i];
       
   303       var tn = child.firstChild.firstChild;
       
   304       if ( tn.nodeValue == this.state )
       
   305         return child.firstChild;
       
   306     }
       
   307     return false;
       
   308   }
       
   309   
       
   310   this.focus_down = function()
       
   311   {
       
   312     var state_td = this.get_state_td();
       
   313     if ( !state_td )
       
   314       return false;
       
   315     if ( state_td.parentNode.nextSibling )
       
   316     {
       
   317       // Ooh boy, DOM stuff can be so complicated...
       
   318       //   <tr>   →   <tr>
       
   319       // ↑ <td>       <td> ↓
       
   320       //   user       user
       
   321       
       
   322       var newstate = state_td.parentNode.nextSibling.firstChild.firstChild.nodeValue;
       
   323       if ( !newstate )
       
   324         return false;
       
   325       this.state = newstate;
       
   326       state_td.className = 'row1';
       
   327       state_td.parentNode.nextSibling.firstChild.className = 'row2';
       
   328       
       
   329       // Exception - automatically scroll around if the item is off-screen
       
   330       var height = $dynano(this.box_id).Height();
       
   331       var top = $dynano(this.box_id).object.scrollTop;
       
   332       var scroll_bottom = height + top;
       
   333       
       
   334       var td_top = $dynano(state_td.parentNode.nextSibling.firstChild).Top() - $dynano(this.box_id).Top();
       
   335       var td_height = $dynano(state_td.parentNode.nextSibling.firstChild).Height();
       
   336       var td_bottom = td_top + td_height;
       
   337       
       
   338       if ( td_bottom > scroll_bottom )
       
   339       {
       
   340         var scrollY = td_top - height + 2*td_height - 7;
       
   341         // window.console.debug(scrollY);
       
   342         $dynano(this.box_id).object.scrollTop = scrollY;
       
   343         /*
       
   344         var newtd = state_td.parentNode.nextSibling.firstChild;
       
   345         var a = document.createElement('a');
       
   346         var id = 'autofill' + Math.floor(Math.random() * 100000);
       
   347         a.name = id;
       
   348         a.id = id;
       
   349         newtd.appendChild(a);
       
   350         window.location.hash = '#' + id;
       
   351         */
       
   352         
       
   353         // In firefox, scrolling like that makes the field get unfocused
       
   354         $dynano(this.field_id).object.focus();
       
   355       }
       
   356     }
       
   357     else
       
   358     {
       
   359       return false;
       
   360     }
       
   361   }
       
   362   
       
   363   this.focus_up = function()
       
   364   {
       
   365     var state_td = this.get_state_td();
       
   366     if ( !state_td )
       
   367       return false;
       
   368     if ( state_td.parentNode.previousSibling && state_td.parentNode.previousSibling.firstChild.tagName != 'TH' )
       
   369     {
       
   370       // Ooh boy, DOM stuff can be so complicated...
       
   371       //   <tr>   ←   <tr>
       
   372       // ↓ <td>       <td> ↑
       
   373       //   user       user
       
   374       
       
   375       var newstate = state_td.parentNode.previousSibling.firstChild.firstChild.nodeValue;
       
   376       if ( !newstate )
       
   377       {
       
   378         return false;
       
   379       }
       
   380       this.state = newstate;
       
   381       state_td.className = 'row1';
       
   382       state_td.parentNode.previousSibling.firstChild.className = 'row2';
       
   383       
       
   384       // Exception - automatically scroll around if the item is off-screen
       
   385       var top = $dynano(this.box_id).object.scrollTop;
       
   386       
       
   387       var td_top = $dynano(state_td.parentNode.previousSibling.firstChild).Top() - $dynano(this.box_id).Top();
       
   388       
       
   389       if ( td_top < top )
       
   390       {
       
   391         $dynano(this.box_id).object.scrollTop = td_top - 10;
       
   392         /*
       
   393         var newtd = state_td.parentNode.previousSibling.firstChild;
       
   394         var a = document.createElement('a');
       
   395         var id = 'autofill' + Math.floor(Math.random() * 100000);
       
   396         a.name = id;
       
   397         a.id = id;
       
   398         newtd.appendChild(a);
       
   399         window.location.hash = '#' + id;
       
   400         */
       
   401         
       
   402         // In firefox, scrolling like that makes the field get unfocused
       
   403         $dynano(this.field_id).object.focus();
       
   404       }
       
   405     }
       
   406     else
       
   407     {
       
   408       $dynano(this.box_id).object.scrollTop = 0;
       
   409       return false;
       
   410     }
       
   411   }
       
   412   
       
   413   this.destroy = function()
       
   414   {
       
   415     this.repeat = false;
       
   416     var body = document.getElementsByTagName('body')[0];
       
   417     var div = document.getElementById(this.box_id);
       
   418     if ( !div )
       
   419       return false;
       
   420     setTimeout('var body = document.getElementsByTagName("body")[0]; body.removeChild(document.getElementById("'+div.id+'"));', 20);
       
   421     // hackish workaround for divs that stick around past their welcoming period
       
   422     for ( var i = 0; i < this.boxes.length; i++ )
       
   423     {
       
   424       var div = document.getElementById(this.boxes[i]);
       
   425       if ( div )
       
   426         setTimeout('var body = document.getElementsByTagName("body")[0]; var div = document.getElementById("'+div.id+'"); if ( div ) body.removeChild(div);', 20);
       
   427       delete(this.boxes[i]);
       
   428     }
       
   429     this.boxes = new Array();
       
   430     this.box_id = false;
       
   431     this.state = false;
       
   432   }
       
   433   
       
   434   this.set = function(val)
       
   435   {
       
   436     var ta = document.getElementById(this.field_id);
       
   437     if ( val )
       
   438       ta.value = val;
       
   439     else if ( this.state )
       
   440       ta.value = this.state;
       
   441     this.destroy();
       
   442     findParentForm($dynano(this.field_id.object))._af_acting = false;
       
   443   }
       
   444   
       
   445   this.sleep = function()
       
   446   {
       
   447     if ( this.box_id )
       
   448     {
       
   449       var div = document.getElementById(this.box_id);
       
   450       div.style.display = 'none';
       
   451     }
       
   452     var el = $dynano(this.field_id).object;
       
   453     var fr = findParentForm(el);
       
   454     el._af_acting = false;
       
   455   }
       
   456   
       
   457   this.wake = function()
       
   458   {
       
   459     if ( this.box_id )
       
   460     {
       
   461       var div = document.getElementById(this.box_id);
       
   462       div.style.display = 'block';
       
   463     }
       
   464   }
       
   465   
       
   466   parent.onblur = function()
       
   467   {
       
   468     af_current = this.afobj;
       
   469     window.setTimeout('if ( af_current ) af_current.sleep(); af_current = false;', 50);
       
   470   }
       
   471   
       
   472   parent.onfocus = function()
       
   473   {
       
   474     af_current = this.afobj;
       
   475     window.setTimeout('if ( af_current ) af_current.wake(); af_current = false;', 50);
       
   476   }
       
   477   
       
   478   parent.afobj = this;
       
   479   var frm = findParentForm(parent);
       
   480   if ( frm.onsubmit )
       
   481   {
       
   482     frm.orig_onsubmit = frm.onsubmit;
       
   483     frm.onsubmit = function(e)
       
   484     {
       
   485       if ( this._af_acting )
       
   486         return false;
       
   487       this.orig_onsubmit(e);
       
   488     }
       
   489   }
       
   490   else
       
   491   {
       
   492     frm.onsubmit = function()
       
   493     {
       
   494       if ( this._af_acting )
       
   495         return false;
       
   496     }
       
   497   }
       
   498   
       
   499   if ( parent.value.length < 3 )
       
   500   {
       
   501     this.destroy();
       
   502     return false;
       
   503   }
       
   504 }
   144 }
   505 
   145 
   506 function findParentForm(o)
   146 function findParentForm(o)
   507 {
   147 {
   508   if ( o.tagName == 'FORM' )
   148   if ( o.tagName == 'FORM' )