/*
 *  Validator.js
 *
 *  A JavaScript object for validating forms.
 *
 *  The form to be validated is passed as an argument to the constructor (and so must
 *  follow the form declaration in the HTML). The type of validation to do is recorded
 *  using the register function. Forms can be validated as strings, integers, positive
 *  integers, integers within a specified range, floating-point numbers (useful for
 *  monetary values), dates (as parseable by Date.parse()), email addresses or groups of
 *  radio buttons or check boxes.
 *
 *  When everything is registered call validate, this is usally done in a form's onSubmit
 *  handler. Validate will check the form and call either the valid function or error
 *  function passed to the constructor, allowing error reporting to be tailored to the
 *  application.
 *
 *  Example use:
 *
 *      function err(e) { alert("Error!"); }
 *      function err(e) { alert("Valid!"); }
 *
 *      v = new Validator(document.form, err, valid);
 *
 *  Note: the constructor must be called after the </form> tag as it is the the form
 *  object is passed to the function rather than just the name.
 *
 *  Afternoon <noon at aftnn.org>, 2002
 *
 */

// IE 5 Mac appears not to support Array.push()!
Array.prototype.push = function (el) { this[this.length] = el; }

// Constructor for Validator objects
function Validator(formToValidate, errorFunction, validFunction) {
    this.errors = 0;

    this.form = formToValidate;
    this.errFunc = errorFunction;
    this.validFunc = validFunction;

    this.elements = new Array();
}

// register names of elements to be validated, specify criteria
Validator.prototype.register = function (element, type, dependency) {
    switch (type) {
        case "int": case "posint": case "email": case "radiogroup": case "checkbox":
        case "select": case "multiselect": case "url":
            this.elements[this.elements.length] = new Array(element, type, dependency);
            break;
        default: this.elements[this.elements.length] = new Array(element, "string", dependency);
    }
}

Validator.prototype.bulk_register = function (elements) {
    if (elements.length > 0)
        for (i=0; i<elements.length; i++) {
            if (elements[i].length > 2) this.register(elements[i][0], elements[i][1], elements[i].slice(2));
            if (elements[i].length == 2) this.register(elements[i][0], elements[i][1]);
            if (elements[i].length == 1) this.register(elements[i][0]);
        }
}

// Work horse function, check on submit
Validator.prototype.validate = function () {
    for (e=0; e<this.elements.length; e++) {
        el = this.elements[e]; vl = this.form[el[0]].value; n = el[0]; d = el[2];
        switch (el[1]) {
            case "int":         this.check_int(n, vl, d);           break;
            case "posint":      this.check_posint(n, vl, d);        break;
            case "email":       this.check_email(n, vl, d);         break;
            case "url":         this.check_url(n, vl, d);           break;
            case "radiogroup":  this.check_radiogroup(n, vl, d);    break;
            case "checkbox":    this.check_checkbox(n, vl, d);      break;
            case "select":      this.check_select(n, vl, d);        break;
            case "multiselect": this.check_multiselect(n, vl, d);   break;
            default:            this.check_string(n, vl, d);
        }
    }

    if (this.errors == 0) return true;
    else {
        this.errors = 0;
        alert("There are problems with the information you have entered.\nPlease check the elements marked with a red cross.");
        return false;
    }
}

// User should have registered a callback function to implement error displaying
Validator.prototype.flag_error = function (name) {
    this.errors++;
    this.errFunc(name);
}

Validator.prototype.flag_valid = function (name) { this.validFunc(name); }

Validator.prototype.required = function (dp) {
    if (dp == null) return true;
    if (dp == false) return false;

    req = true;
    rgroups = new String();

    for (i=0; i<this.form.length; i++) if (this.form[i].type == "radio" && rgroups.indexOf(this.form[i].name + ",") == -1) rgroups += this.form[i].name + ",";

    for (i=0; i<dp.length; i+=2) {
        if (rgroups.indexOf(dp[i]) != -1) {
            for (j=0; j<this.form.length; j++)
                if (this.form[j].type == "radio" && this.form[j].value == dp[i+1] &&
                    this.form[j].name == dp[0] && this.form[j].checked) req = false;
        }
        else {
            if ((dp[i+1] == "checked" && this.form[dp[i]].checked) ||
                (dp[i+1] == "unchecked" && this.form[dp[i]].checked == false) ||
                (dp[i+1] == "*" && this.form[dp[i]].value != "") ||
                (this.form[dp[i]].value == dp[i+1]))
                req = false;
        }
    }

    return req;
}

Validator.prototype.check_string = function (name, value, dependency) {
    if (this.required(dependency) && value == "") this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_int = function (name, value, dependency) {
    if (this.required(dependency) && isNaN(parseInt(value, 10))) this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_posint = function (name, value, dependency) {
    i = parseInt(value, 10);
    if (this.required(dependency) && (isNaN(i) || i < 0)) this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_email = function (name, value, dependency) {
    if (this.required(dependency) && new String(value).search(/^[\.\w-]+@[a-zA-Z0-9][\w-]+(\.[a-zA-Z0-9][\w-]+)+$/) == -1) this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_url = function (name, value, dependency) {
    if (this.required(dependency) && new String(value).search(/^http:\/\/([\.\w-\:]+@)?[a-zA-Z0-9][\w-]+(\.[a-zA-Z0-9][\w-]+)+(\/.+)?$/) == -1) this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_radiogroup = function (name, value, dependency) {
    valid = false;

    if (this.required(dependency)) {
        // find a radio button with the given name that is checked, otherwise group is invalid
        for (i=0; i<this.form.length; i++) if (this.form[i].type == "radio" && this.form[i].name == name && this.form[i].checked == true) valid = true;

        if (!valid) this.flag_error(name);
        else this.flag_valid(name);
    }
    else this.flag_valid(name);
}

Validator.prototype.check_checkbox = function (name, value, dependency) {
    if (this.required(dependency) && !this.form[name].checked) this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_select = function (name, value, dependency) {
    if (this.required(dependency) && this.form[name].options[this.form[name].selectedIndex].value == "") this.flag_error(name);
    else this.flag_valid(name);
}

Validator.prototype.check_multiselect = function (name, value, dependency) {
    if (this.required(dependency)) {
        valid = false;
        for (i=0; i<this.form[name].length; i++) if (this.form[name].options[i].selected == true) valid = true;

        if (this.form[name].value == "") this.flag_error(name);
        else this.flag_valid(name);
    }
    else this.flag_valid(name);
}


/*
 *  Function to gather the data from complex input controls (calendar, time drop-downs)
 *  and format it as a string suitable for passing back to the server.
 */

function mkdate(out, d, m, y) {
    if (d < 10) d = "0" + d;
    if (m < 10) m = "0" + m;
    document.forms[0].elements[out].value = d + "/" + m + "/" + y;
}

function mktime(out, prefix) {
    df = document.forms[0].elements;
    h = parseInt(df[prefix + "hours"].value, 10);
    m = parseInt(df[prefix + "mins"].value, 10);

    if (h >= 0 && h < 24 && m >= 0 && m < 60) {
        if (m < 10) m = "0" + m;
        if (h < 10) h = "0" + h;

        df[out].value = h + ":" + m;
    }
    else df[out].value = "";
}

function checkLength(el, len, name) {
    if (el.value.length > len) alert("The limit for the \"" + name + "\" field value is " + len + " characters. You have entered " + el.value.length + " characters.\n\nThe extra " + (len - el.value.length) + " characters will be removed unless you amend the value before submitting this form.");
}
		
aftnn.orgcontentcode → validator