--- a/includes/clientside/static/acl.js Sun Oct 07 22:06:15 2007 -0400
+++ b/includes/clientside/static/acl.js Sun Oct 14 20:51:15 2007 -0400
@@ -128,7 +128,7 @@
usrsel = document.createElement('input');
usrsel.type = 'text';
usrsel.name = 'username';
- usrsel.onkeyup = function() { ajaxUserNameComplete(this); };
+ usrsel.onkeyup = function() { new AutofillUsername(this, undefined, true); };
usrsel.id = 'userfield_' + aclManagerID;
try {
usrsel.setAttribute("autocomplete","off");
--- a/includes/clientside/static/autocomplete.js Sun Oct 07 22:06:15 2007 -0400
+++ b/includes/clientside/static/autocomplete.js Sun Oct 14 20:51:15 2007 -0400
@@ -160,7 +160,24 @@
thediv.id = id;
unObj.onblur = function() { destroyUsernameDropdowns(); }
- eval(ajax.responseText);
+ var response = String(ajax.responseText) + ' ';
+ if ( response.substr(0,1) != '{' )
+ {
+ new messagebox(MB_OK|MB_ICONSTOP, 'Invalid response', 'Invalid or unexpected JSON response from server:<pre>' + ajax.responseText + '</pre>');
+ return false;
+ }
+
+ response = parseJSON(response);
+ var errorstring = false;
+ if ( response.mode == 'error' )
+ {
+ errorstring = response.error;
+ }
+ else
+ {
+ var userlist = response.users_real;
+ }
+
if(errorstring)
{
html = '<span style="color: #555; padding: 4px;">'+errorstring+'</span>';
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/autofill.js Sun Oct 14 20:51:15 2007 -0400
@@ -0,0 +1,512 @@
+/**
+ * Javascript auto-completion for form fields.
+ */
+
+var af_current = false;
+
+function AutofillUsername(parent, event, allowanon)
+{
+ // if this is IE, use the old code
+ if ( IE )
+ {
+ ajaxUserNameComplete(parent);
+ return false;
+ }
+ if ( parent.afobj )
+ {
+ parent.afobj.go();
+ return true;
+ }
+
+ parent.autocomplete = 'off';
+ parent.setAttribute('autocomplete', 'off');
+
+ this.repeat = false;
+ this.event = event;
+ this.box_id = false;
+ this.boxes = new Array();
+ this.state = false;
+ this.allowanon = ( allowanon ) ? true : false;
+
+ if ( !parent.id )
+ parent.id = 'afuser_' + Math.floor(Math.random() * 1000000);
+
+ this.field_id = parent.id;
+
+ // constants
+ this.KEY_UP = 38;
+ this.KEY_DOWN = 40;
+ this.KEY_ESC = 27;
+ this.KEY_TAB = 9;
+ this.KEY_ENTER = 13;
+
+ // response cache
+ this.responses = new Object();
+
+ // ajax placeholder
+ this.process_dataset = function(resp_json)
+ {
+ // window.console.info('Processing the following dataset.');
+ // window.console.debug(resp_json);
+ var autofill = this;
+
+ if ( typeof(autofill.event) == 'object' )
+ {
+ if ( autofill.event.keyCode )
+ {
+ if ( autofill.event.keyCode == autofill.KEY_ENTER && autofill.boxes.length < 1 && !autofill.box_id )
+ {
+ // user hit enter after accepting a suggestion - submit the form
+ var frm = findParentForm($(autofill.field_id).object);
+ frm._af_acting = false;
+ frm.submit();
+ // window.console.info('Submitting form');
+ return false;
+ }
+ 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 )
+ {
+ autofill.keyhandler();
+ // window.console.info('Control key detected, called keyhandler and exiting');
+ return true;
+ }
+ }
+ }
+
+ if ( this.box_id )
+ {
+ this.destroy();
+ // window.console.info('already have a box open - destroying and exiting');
+ //return false;
+ }
+
+ var users = new Array();
+ for ( var i = 0; i < resp_json.users_real.length; i++ )
+ {
+ try
+ {
+ var user = resp_json.users_real[i].toLowerCase();
+ var inp = $(autofill.field_id).object.value;
+ inp = inp.toLowerCase();
+ if ( user.indexOf(inp) > -1 )
+ {
+ users.push(resp_json.users_real[i]);
+ }
+ }
+ catch(e)
+ {
+ users.push(resp_json.users_real[i]);
+ }
+ }
+
+ // This was used ONLY for debugging the DOM and list logic
+ // resp_json.users = resp_json.users_real;
+
+ // construct table
+ var div = document.createElement('div');
+ div.className = 'tblholder';
+ div.style.clip = 'rect(0px,auto,auto,0px)';
+ div.style.maxHeight = '200px';
+ div.style.overflow = 'auto';
+ div.style.zIndex = '9999';
+ var table = document.createElement('table');
+ table.border = '0';
+ table.cellSpacing = '1';
+ table.cellPadding = '3';
+
+ var tr = document.createElement('tr');
+ var th = document.createElement('th');
+ th.appendChild(document.createTextNode('Username suggestions'));
+ tr.appendChild(th);
+ table.appendChild(tr);
+
+ if ( users.length < 1 )
+ {
+ var tr = document.createElement('tr');
+ var td = document.createElement('td');
+ td.className = 'row1';
+ td.appendChild(document.createTextNode('No suggestions'));
+ td.afobj = autofill;
+ tr.appendChild(td);
+ table.appendChild(tr);
+ }
+ else
+
+ for ( var i = 0; i < users.length; i++ )
+ {
+ var user = users[i];
+ var tr = document.createElement('tr');
+ var td = document.createElement('td');
+ td.className = ( i == 0 ) ? 'row2' : 'row1';
+ td.appendChild(document.createTextNode(user));
+ td.afobj = autofill;
+ td.style.cursor = 'pointer';
+ td.onclick = function()
+ {
+ this.afobj.set(this.firstChild.nodeValue);
+ }
+ tr.appendChild(td);
+ table.appendChild(tr);
+ }
+
+ // Finalize div
+ var tb_top = $(autofill.field_id).Top();
+ var tb_height = $(autofill.field_id).Height();
+ var af_top = tb_top + tb_height - 9;
+ var tb_left = $(autofill.field_id).Left();
+ var af_left = tb_left;
+
+ div.style.position = 'absolute';
+ div.style.left = af_left + 'px';
+ div.style.top = af_top + 'px';
+ div.style.width = '200px';
+ div.style.fontSize = '7pt';
+ div.style.fontFamily = 'Trebuchet MS, arial, helvetica, sans-serif';
+ div.id = 'afuserdrop_' + Math.floor(Math.random() * 1000000);
+ div.appendChild(table);
+
+ autofill.boxes.push(div.id);
+ autofill.box_id = div.id;
+ if ( users.length > 0 )
+ autofill.state = users[0];
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(div);
+
+ autofill.repeat = true;
+ }
+
+ // perform ajax call
+ this.fetch_and_process = function()
+ {
+ af_current = this;
+ var processResponse = function()
+ {
+ if ( ajax.readyState == 4 )
+ {
+ var afobj = af_current;
+ af_current = false;
+ // parse the JSON response
+ var response = String(ajax.responseText) + ' ';
+ if ( response.substr(0,1) != '{' )
+ {
+ new messagebox(MB_OK|MB_ICONSTOP, 'Invalid response', 'Invalid or unexpected JSON response from server:<pre>' + ajax.responseText + '</pre>');
+ return false;
+ }
+ if ( $(afobj.field_id).object.value.length < 3 )
+ return false;
+ var resp_json = parseJSON(response);
+ var resp_code = $(afobj.field_id).object.value.toLowerCase().substr(0, 3);
+ afobj.responses[resp_code] = resp_json;
+ afobj.process_dataset(resp_json);
+ }
+ }
+ var usernamefragment = ajaxEscape($(this.field_id).object.value);
+ ajaxGet(stdAjaxPrefix + '&_mode=fillusername&name=' + usernamefragment + '&allowanon=' + ( this.allowanon ? '1' : '0' ), processResponse);
+ }
+
+ this.go = function()
+ {
+ if ( document.getElementById(this.field_id).value.length < 3 )
+ {
+ this.destroy();
+ return false;
+ }
+
+ if ( af_current )
+ return false;
+
+ var resp_code = $(this.field_id).object.value.toLowerCase().substr(0, 3);
+ if ( this.responses.length < 1 || ! this.responses[ resp_code ] )
+ {
+ // window.console.info('Cannot find dataset ' + resp_code + ' in cache, sending AJAX request');
+ this.fetch_and_process();
+ }
+ else
+ {
+ // window.console.info('Using cached dataset: ' + resp_code);
+ var resp_json = this.responses[ resp_code ];
+ this.process_dataset(resp_json);
+ }
+ document.getElementById(this.field_id).onkeyup = function(event)
+ {
+ this.afobj.event = event;
+ this.afobj.go();
+ }
+ document.getElementById(this.field_id).onkeydown = function(event)
+ {
+ var form = findParentForm(this);
+ if ( typeof(event) != 'object' )
+ var event = window.event;
+ if ( typeof(event) == 'object' )
+ {
+ if ( event.keyCode == this.afobj.KEY_ENTER && this.afobj.boxes.length < 1 && !this.afobj.box_id )
+ {
+ // user hit enter after accepting a suggestion - submit the form
+ form._af_acting = false;
+ return true;
+ }
+ }
+ form._af_acting = true;
+ }
+ }
+
+ this.keyhandler = function()
+ {
+ var key = this.event.keyCode;
+ if ( key == this.KEY_ENTER && !this.repeat )
+ {
+ var form = findParentForm($(this.field_id).object);
+ form._af_acting = false;
+ return true;
+ }
+ switch(key)
+ {
+ case this.KEY_UP:
+ this.focus_up();
+ break;
+ case this.KEY_DOWN:
+ this.focus_down();
+ break;
+ case this.KEY_ESC:
+ this.destroy();
+ break;
+ case this.KEY_TAB:
+ this.destroy();
+ break;
+ case this.KEY_ENTER:
+ this.set();
+ break;
+ }
+
+ var form = findParentForm($(this.field_id).object);
+ form._af_acting = false;
+ }
+
+ this.get_state_td = function()
+ {
+ var div = document.getElementById(this.box_id);
+ if ( !div )
+ return false;
+ if ( !this.state )
+ return false;
+ var table = div.firstChild;
+ for ( var i = 1; i < table.childNodes.length; i++ )
+ {
+ // the table is DOM-constructed so no cruddy HTML hacks :-)
+ var child = table.childNodes[i];
+ var tn = child.firstChild.firstChild;
+ if ( tn.nodeValue == this.state )
+ return child.firstChild;
+ }
+ return false;
+ }
+
+ this.focus_down = function()
+ {
+ var state_td = this.get_state_td();
+ if ( !state_td )
+ return false;
+ if ( state_td.parentNode.nextSibling )
+ {
+ // Ooh boy, DOM stuff can be so complicated...
+ // <tr> --> <tr>
+ // <td> <td>
+ // user user
+
+ var newstate = state_td.parentNode.nextSibling.firstChild.firstChild.nodeValue;
+ if ( !newstate )
+ return false;
+ this.state = newstate;
+ state_td.className = 'row1';
+ state_td.parentNode.nextSibling.firstChild.className = 'row2';
+
+ // Exception - automatically scroll around if the item is off-screen
+ var height = $(this.box_id).Height();
+ var top = $(this.box_id).object.scrollTop;
+ var scroll_bottom = height + top;
+
+ var td_top = $(state_td.parentNode.nextSibling.firstChild).Top() - $(this.box_id).Top();
+ var td_height = $(state_td.parentNode.nextSibling.firstChild).Height();
+ var td_bottom = td_top + td_height;
+
+ if ( td_bottom > scroll_bottom )
+ {
+ var scrollY = td_top - height + 2*td_height - 7;
+ // window.console.debug(scrollY);
+ $(this.box_id).object.scrollTop = scrollY;
+ /*
+ var newtd = state_td.parentNode.nextSibling.firstChild;
+ var a = document.createElement('a');
+ var id = 'autofill' + Math.floor(Math.random() * 100000);
+ a.name = id;
+ a.id = id;
+ newtd.appendChild(a);
+ window.location.hash = '#' + id;
+ */
+
+ // In firefox, scrolling like that makes the field get unfocused
+ $(this.field_id).object.focus();
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ this.focus_up = function()
+ {
+ var state_td = this.get_state_td();
+ if ( !state_td )
+ return false;
+ if ( state_td.parentNode.previousSibling && state_td.parentNode.previousSibling.firstChild.tagName != 'TH' )
+ {
+ // Ooh boy, DOM stuff can be so complicated...
+ // <tr> <-- <tr>
+ // <td> <td>
+ // user user
+
+ var newstate = state_td.parentNode.previousSibling.firstChild.firstChild.nodeValue;
+ if ( !newstate )
+ {
+ return false;
+ }
+ this.state = newstate;
+ state_td.className = 'row1';
+ state_td.parentNode.previousSibling.firstChild.className = 'row2';
+
+ // Exception - automatically scroll around if the item is off-screen
+ var top = $(this.box_id).object.scrollTop;
+
+ var td_top = $(state_td.parentNode.previousSibling.firstChild).Top() - $(this.box_id).Top();
+
+ if ( td_top < top )
+ {
+ $(this.box_id).object.scrollTop = td_top - 10;
+ /*
+ var newtd = state_td.parentNode.previousSibling.firstChild;
+ var a = document.createElement('a');
+ var id = 'autofill' + Math.floor(Math.random() * 100000);
+ a.name = id;
+ a.id = id;
+ newtd.appendChild(a);
+ window.location.hash = '#' + id;
+ */
+
+ // In firefox, scrolling like that makes the field get unfocused
+ $(this.field_id).object.focus();
+ }
+ }
+ else
+ {
+ $(this.box_id).object.scrollTop = 0;
+ return false;
+ }
+ }
+
+ this.destroy = function()
+ {
+ this.repeat = false;
+ var body = document.getElementsByTagName('body')[0];
+ var div = document.getElementById(this.box_id);
+ if ( !div )
+ return false;
+ setTimeout('var body = document.getElementsByTagName("body")[0]; body.removeChild(document.getElementById("'+div.id+'"));', 20);
+ // hackish workaround for divs that stick around past their welcoming period
+ for ( var i = 0; i < this.boxes.length; i++ )
+ {
+ var div = document.getElementById(this.boxes[i]);
+ if ( div )
+ setTimeout('var body = document.getElementsByTagName("body")[0]; var div = document.getElementById("'+div.id+'"); if ( div ) body.removeChild(div);', 20);
+ delete(this.boxes[i]);
+ }
+ this.box_id = false;
+ this.state = false;
+ }
+
+ this.set = function(val)
+ {
+ var ta = document.getElementById(this.field_id);
+ if ( val )
+ ta.value = val;
+ else if ( this.state )
+ ta.value = this.state;
+ this.destroy();
+ }
+
+ this.sleep = function()
+ {
+ if ( this.box_id )
+ {
+ var div = document.getElementById(this.box_id);
+ div.style.display = 'none';
+ }
+ var el = $(this.field_id).object;
+ var fr = findParentForm(el);
+ el._af_acting = false;
+ }
+
+ this.wake = function()
+ {
+ if ( this.box_id )
+ {
+ var div = document.getElementById(this.box_id);
+ div.style.display = 'block';
+ }
+ }
+
+ parent.onblur = function()
+ {
+ af_current = this.afobj;
+ window.setTimeout('if ( af_current ) af_current.sleep(); af_current = false;', 50);
+ }
+
+ parent.onfocus = function()
+ {
+ af_current = this.afobj;
+ window.setTimeout('if ( af_current ) af_current.wake(); af_current = false;', 50);
+ }
+
+ parent.afobj = this;
+ var frm = findParentForm(parent);
+ if ( frm.onsubmit )
+ {
+ frm.orig_onsubmit = frm.onsubmit;
+ frm.onsubmit = function(e)
+ {
+ if ( this._af_acting )
+ return false;
+ this.orig_onsubmit(e);
+ }
+ }
+ else
+ {
+ frm.onsubmit = function()
+ {
+ if ( this._af_acting )
+ return false;
+ }
+ }
+
+ if ( parent.value.length < 3 )
+ {
+ this.destroy();
+ return false;
+ }
+}
+
+function findParentForm(o)
+{
+ if ( o.tagName == 'FORM' )
+ return o;
+ while(true)
+ {
+ o = o.parentNode;
+ if ( !o )
+ return false;
+ if ( o.tagName == 'FORM' )
+ return o;
+ }
+ return false;
+}
+
--- a/includes/clientside/static/enano-lib-basic.js Sun Oct 07 22:06:15 2007 -0400
+++ b/includes/clientside/static/enano-lib-basic.js Sun Oct 14 20:51:15 2007 -0400
@@ -264,6 +264,7 @@
'admin-menu.js',
'ajax.js',
'autocomplete.js',
+ 'autofill.js',
'base64.js',
'dropdown.js',
'faders.js',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/stpatty/css-extra/ie-fixes-shamrock.css Sun Oct 14 20:51:15 2007 -0400
@@ -0,0 +1,23 @@
+/*
+ * St. Patty theme for Enano
+ * Copyright (C) 2007 Dan Fuhry
+ *
+ * This theme is Free Software, available under the terms of the GNU General Public License. See the file "GPL" included with this
+ * package for details.
+ */
+
+div#bg {
+ background-image: none;
+}
+div#title {
+ /* background-image: none; */
+}
+div#rap {
+ background-image: url(../images/rap-ie.gif);
+}
+div#sidebar ul li a {
+ margin-bottom: -14px;
+}
+div#pagetools a {
+ padding: 4px 3px;
+}
--- a/themes/stpatty/css-extra/ie-fixes.css Sun Oct 07 22:06:15 2007 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * St. Patty theme for Enano
- * Copyright (C) 2007 Dan Fuhry
- *
- * This theme is Free Software, available under the terms of the GNU General Public License. See the file "GPL" included with this
- * package for details.
- */
-
-div#bg {
- background-image: none;
-}
-div#title {
- /* background-image: none; */
-}
-div#rap {
- background-image: url(../images/rap-ie.gif);
-}
-div#sidebar ul li a {
- margin-bottom: -14px;
-}
-div#pagetools a {
- padding: 4px 3px;
-}
--- a/themes/stpatty/header.tpl Sun Oct 07 22:06:15 2007 -0400
+++ b/themes/stpatty/header.tpl Sun Oct 14 20:51:15 2007 -0400
@@ -9,7 +9,7 @@
<!-- This script automatically loads the other 15 JS files -->
<script type="text/javascript" src="{SCRIPTPATH}/includes/clientside/static/enano-lib-basic.js"></script>
<!--[if lt IE 7]>
- <link rel="stylesheet" type="text/css" href="{SCRIPTPATH}/themes/{THEME_ID}/css-extra/ie-fixes.css" />
+ <link rel="stylesheet" type="text/css" href="{SCRIPTPATH}/themes/{THEME_ID}/css-extra/ie-fixes-{STYLE_ID}.css" />
<![endif]-->
<script type="text/javascript">
// <![CDATA[