# HG changeset patch # User Dan # Date 1192409475 14400 # Node ID 9dbbec5e6096c6a3b18db93cf8be1682db5d2f48 # Parent c69730750be34cd42fdd7a28ac62907589f7d937# Parent b796208d050dfc1de9cae411ae73682e1513d570 Sync from stable diff -r c69730750be3 -r 9dbbec5e6096 ajax.php diff -r c69730750be3 -r 9dbbec5e6096 includes/clientside/static/acl.js --- 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"); diff -r c69730750be3 -r 9dbbec5e6096 includes/clientside/static/autocomplete.js --- 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:
' + ajax.responseText + '
'); + return false; + } + + response = parseJSON(response); + var errorstring = false; + if ( response.mode == 'error' ) + { + errorstring = response.error; + } + else + { + var userlist = response.users_real; + } + if(errorstring) { html = ''+errorstring+''; diff -r c69730750be3 -r 9dbbec5e6096 includes/clientside/static/autofill.js --- /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:
' + ajax.responseText + '
'); + 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... + // --> + // + // 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... + // <-- + // + // 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; +} + diff -r c69730750be3 -r 9dbbec5e6096 includes/clientside/static/enano-lib-basic.js --- 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', diff -r c69730750be3 -r 9dbbec5e6096 includes/functions.php diff -r c69730750be3 -r 9dbbec5e6096 includes/template.php diff -r c69730750be3 -r 9dbbec5e6096 index.php diff -r c69730750be3 -r 9dbbec5e6096 plugins/SpecialAdmin.php diff -r c69730750be3 -r 9dbbec5e6096 plugins/admin/PageGroups.php diff -r c69730750be3 -r 9dbbec5e6096 themes/stpatty/css-extra/ie-fixes-shamrock.css --- /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; +} diff -r c69730750be3 -r 9dbbec5e6096 themes/stpatty/css-extra/ie-fixes.css --- 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; -} diff -r c69730750be3 -r 9dbbec5e6096 themes/stpatty/header.tpl --- 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 @@