/*
 * Tested and operational under:
 *     Firefox 3.0.7, IE 7, Google Chrome 1.0.154, Opera 9.64, Safari 3.2.2
 *
 * Functionality includes:
 *    autoTab between related fields (adjacent fields with class="autoTab")
 *    User manual tab entered immediately after an autoTab even is discarded
 *        treated as if we didn't autotab and the user initiated the tab field
 *        move
 *    Backspace from the first position in an adjacent autoTab field will trigger
 *        the deletion of the last character in the previous adjacent autoTab
 *        field
 *
 * Special CSS:
 *    autoTab: general class identifying a field as autoTab enabled.  These will
 *             get autowired with the required event hooks to process autoTab
 *             functionality.
 *    autoTabFirst: field will not allow auto-backspace to previous form field
 *    autoTabLast:  field will not autoTab into next form field
 */

    // Used to track last autotab to differentiate between whether to ignore a
    // user tab keypress
    autoTabLastLeave = null;

    // Length of time during which a tab keypress will be ignored.  One keypress
    // resets the autoTabLastLeave interval so that two presses in quick
    // succession moves the cursor to the next field
    tabIgnoreInterval = 500; // .5 sec

    /* Required to properly place cursor at end of text field for IE.  Firefox
     * and other browsers appear to default to this mode
     */
    function setCursorToEnd(elem){
        elem.value = elem.value;
    }

    function getIndex(input) {
        var index = -1, i = 0, found = false;
        while (i < input.form.length && index == -1)
        if (input.form[i] == input)index = i;
        else i++;
        return index;
    }

    function autoTabOnUp(event) {
        if (!event) var event = window.event;
        if (event.target) elem = event.target;
        else if (event.srcElement) elem = event.srcElement;
        if (elem.nodeType == 3) // defeat Safari bug
            elem = elem.parentNode;
        var keyCode = event.charCode?event.charCode:event.keyCode;

        if (elem.value.length == elem.maxLength && (
             (keyCode >= 48 && keyCode <= 90) ||
                 (keyCode >= 96 && keyCode <= 105)
             ))
        {
             var nextElement = elem.form[(getIndex(elem)+1) % elem.form.length];
             if (elem.className.indexOf("autoTabLast") == -1) {
                var mytabindex = elem.tabIndex;
                var myformelements = elem.form.elements;
                nextElement.focus();
                autoTabLastLeave = new Date();
             }
        }
    }

    function autoTabOnDown(event) {
        if (!event) var event = window.event;
        if (event.target) elem = event.target;
        else if (event.srcElement) elem = event.srcElement;
        if (elem.nodeType == 3) // defeat Safari bug
            elem = elem.parentNode;
        var keyCode = event.charCode?event.charCode:event.keyCode;

        if (keyCode == 8 && elem.value.length==0)
        {
             var prevElement = elem.form[(getIndex(elem)-1) % elem.form.length];
             if (elem.className.indexOf("autoTabFirst") == -1) {
                 var mytabindex = elem.tabIndex;
                 var myformelements = elem.form.elements;
                 prevElement.focus();
                 setCursorToEnd(prevElement);
             }
        }

        if (autoTabLastLeave && (((new Date()).getTime() -
                autoTabLastLeave.getTime()) < tabIgnoreInterval)) {
            if (keyCode == 9 && elem.value.length < elem.maxLength)
            {
                var mytabindex = elem.tabIndex;
                var myformelements = elem.form.elements;
                elem.form[(getIndex(elem)-1) % elem.form.length].focus();
               autoTabLastLeave = null;
            }
        }
    }

    function getElementsByClassName(root, cl) {
        var retnode = [];
        var myclass = new RegExp('\\b'+cl+'\\b');
        var elem = root.getElementsByTagName('*');
        for (var i = 0; i < elem.length; i++) {
            var classes = elem[i].className;
            if (myclass.test(classes)) retnode.push(elem[i]);
        }
        return retnode;
    };

    /* Logic here borrowed from drupal.  Another alternative if this causes
    troubles can be found at http://ejohn.org/projects/flexible-javascript-events/ */
    function addEvent(target, eventName, func, bubble) {
        if(document.addEventListener) {
            target.addEventListener(eventName, func, bubble);
        } else if(document.attachEvent) {
            target.attachEvent("on" + eventName, func);
        }
    }

var oldLoad = window.onload;
window.onload = function() {
    var fields = getElementsByClassName(document, "autoTab");
    for (i=0; i<fields.length; i++) {
        addEvent(fields[i],'keydown', autoTabOnDown, false);
        addEvent(fields[i],'keyup', autoTabOnUp, false);
    }
    
    //Call any previous configured hook
    if (oldLoad) oldLoad;
}
