// form_autofocus.js
//
// To use, place this file within your Web site, and include the following in
// the <head> section of your document, with $PATH changed to the URL path
// (Web address, not internal path name) where you have installed this file:
// 
//    <script type="text/javascript" src="/$PATH/form_autofocus.js"></script>
//
// This script will automatically move the input focus (the user's cursor) to
// what looks like the most reasonable place for it.  The script's order of
// preference for where it will move focus is:
//
//    1) Empty text, textarea, and password inputs
//    2) Text, textarea, and password inputs with text in them
//    3) File inputs
//    4) Select inputs (single or multiple)
//    5) Radio button and checkbox inputs
//
// Input focus is moved using the onload event, and so will occur when page
// load is complete.  If it appears that the user has interacted with the
// page -- if any form inputs are not in their default state, including
// hidden inputs -- focus will not be changed.  This is to avoid the annoying
// case where you've already started typing into a form input, but a script
// interferes with what you're doing.
//
// The script will select the first input it encounters (in the order they
// are reported by the browser, which is generally the order they were
// defined in) out of the most preferred type of input it finds.  Non-visible
// form elements are excluded from consideration entirely, since focus cannot
// be successfully moved to them.
//
// You can alter the script's behavior in four ways.
//
//   1) You can set the variable document.focusOverride to a form input
//      object; this will make the script focus on that input instead of one
//      it selects.
//   2) You can include the class 'nofocus' on inputs; this will make the
//      script skip them for purposes of selecting what to focus on.
//   3) You can include the class 'wantfocus' on inputs; the script will
//      preferentially select inputs with this class.  (If two inputs both
//      have 'wantfocus', the preference list above applies to them.)
//   4) You can include the class 'focusignore' on inputs.  This makes the
//      script ignore the input for purposes of determining whether the user
//      has interacted with the page.
//
// This script is known to work under IE 6, IE 7, Firefox 2, and Safari 3.
// This includes handling the case where a window is opened in a new tab that
// does not immediately receive window focus, which requires special treatment
// for some browsers.
//
// Official home: http://lostsouls.org/grimoire_form_autofocus.  Any updates
// will be found there.
//
// v1.0   2007-09-24, Chaos of Lost Souls MUD, http://lostsouls.org/
// v1.1   2007-10-05, Chaos: refactoring, cleanup, unload on completion
// v1.1.1 2007-12-25, Chaos: don't break if a form element has no classname
// v1.2   2008-06-03, Chaos: detecting and handling non-visible form elements
// v1.2.1 2008-07-02, Chaos: fixed logic error on multiple select boxes
//
// This code is released into the public domain.

// This information is provided AS IS and any express or implied warranties,
// including, but not limited to, the implied warranties of merchantability
// and fitness for a particular purpose are disclaimed. In no event shall the
// author or publisher be liable for any damages of any kind, however caused
// and on any theory of liability, arising in any way out of the use of this
// information, even if advised of the possibility of such damage.

if(window) {
    var formAutoFocus = function() {
        var focusTarget;
        var focusFlag;
        var focusDone = function() {
            focusFlag = true;
        }
        var attachFocus = function() {
            if(focusTarget.attachEvent) {
                focusTarget.attachEvent('onfocus', focusDone);
            } else {
                focusTarget.prevOnFocus = focusTarget.onfocus;
                if(focusTarget.prevOnFocus) {
                    var dualFocus = function() {
                        focusTarget.prevOnFocus();
                        focusDone();
                    }
                    focusTarget.onfocus = dualFocus;
                } else {
                    focusTarget.onfocus = focusDone;
                }
            }
        }
        var detachFocus = function() {
            if(focusTarget.attachEvent) {
                focusTarget.detachEvent('onfocus', focusDone);
            } else {
                focusTarget.onfocus = focusTarget.prevOnFocus;
                focusTarget.prevOnFocus = null;
            }
        }
        var checkFocus = function() {
            detachFocus();
            if(focusFlag)
                window.formAutoFocus = null;
            else
                window.setTimeout(formAutoFocus, 50);
        }
        var tryFocus = function(obj) {
            focusTarget = obj;
            focusFlag = false;
            attachFocus();
            try {
                focusTarget.focus();
            } catch(error) {
                return;
            }
            if(focusFlag) {
                detachFocus();
                formAutoFocus = null;
                return;
            }
            window.setTimeout(checkFocus, 10);
        }
        var skip = function(obj) {
            return elem.classname && elem.classname.match(/\bfocusignore\b/);
        }
        if(document.focusOverride) {
            tryFocus(document.focusOverride);
            return;
        }
        var tiers = new Array;
        for(var i = 0; i < document.forms.length; i++) {
            var form = document.forms[i];
            for(var j = 0; j < form.elements.length; j++) {
                var elem = form.elements[j];
                if(!elem.focus)
                    continue;
                if(!elem.offsetWidth)
                    continue;
                var tier;
                switch(elem.type) {
                case 'text'           :
                case 'textarea'       :
                case 'password'       :
                    if(elem.value != elem.defaultValue && !skip(elem))
                        return;
                    tier = elem.value ? 1 : 0;
                    break;
                case 'file'           :
                    if(elem.value != elem.defaultValue && !skip(elem))
                        return;
                    tier = 2;
                    break;
                case 'select-one'     :
                    if(!skip(elem)) {
                        var anyDefault = false;
                        for(var k = 0; k < elem.options.length; k++) {
                            if(elem.options[k].defaultSelected) {
                                anyDefault = true;
                                break;
                            }
                        }
                        if(anyDefault) {
                            for(var k = 0; k < elem.options.length; k++) {
                                var opt = elem.options[k];
                                if(opt.selected != opt.defaultSelected)
                                    return;
                            }
                        } else {
                            if(elem.selectedIndex != 0)
                                return;
                        }
                    }
                    tier = 3;
                    break;
                case 'select-multiple':
                    if(!skip(elem)) {
                        for(var k = 0; k < elem.options.length; k++) {
                            var opt = elem.options[k];
                            if(opt.selected != opt.defaultSelected)
                                return;
                        }
                    }
                    tier = 3;
                    break;
                case 'radio'          :
                case 'checkbox'       :
                    if(elem.selected != elem.defaultSelected && !skip(elem))
                        return;
                    tier = 4;
                    break;
                case 'hidden'         :
                    if(elem.value != elem.defaultValue && !skip(elem))
                        return;
                    continue;
                default               :
                    continue;
                }
                if(!tiers[0] && !elem.className.match(/\bnofocus\b/)) {
                    var wantfocus = elem.className.match(/\bwantfocus\b/);
                    if(!wantfocus)
                        tier += 5;
                    if(!tiers[tier])
                        tiers[tier] = elem;
                }
            }
        }
        for(var ix = 0; ix < tiers.length; ix++) {
            if(tiers[ix]) {
                tryFocus(tiers[ix]);
                break;
            }
        }
    }
    if(window.attachEvent) {
        window.attachEvent('onload', formAutoFocus);
    } else {
        if(window.onload) {
            var curronload = window.onload;
            var newonload = function() {
                curronload();
                formAutoFocus();
            };
            window.onload = newonload;
        } else {
            window.onload = formAutoFocus;
        }
    }
}