// Invalid/missing elements are highlighted using // this background colour: var MJS_COLOUR_ERROR = '#ffdddd'; // Indexes into validation param hash for each validated element, // first general ones, then those specifi to type: var MJS_TYPE = 0; var MJS_NAME = 1; // display name var MJS_REQUIRED = 2; var MJS_REGEXP = 3; var MJS_name = 4; // 'real' name var MJS_TEXT_MIN = 4; var MJS_TEXT_MAX = 5; var MJS_TEXT_REQ_IF = 6; var MJS_TEXTAREA_REQ_IF = 4; var MJS_SEL_IGNORE_FIRST = 3; // Select element has hint as first option - // ignore when looking for value var MJS_SEL_REQ_IF = 4; var MJS_DATE_REQ_IF = 3; var MJS_DATE_RANGE_START = 4; var MJS_DEFAULT_REQ_IF = 3; var MOCA_REGEXP_all = ''; var MOCA_REGEXP_words = /^[a-z 0-9]+$/i; var MOCA_REGEXP_alphanumeric = /^[a-z0-9_]+$/i; var MOCA_REGEXP_alphanumericplusspace = /^[a-z0-9_ -]+$/i; var MOCA_REGEXP_filename = /^[a-z0-9_.-]+$/i; var MOCA_REGEXP_email = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4})+$/; var MOCA_REGEXP_phone = /^[0-9 +\(\)-]{7,}$/; var MOCA_REGEXP_integer = /^[0-9]+$/; var MOCA_REGEXP_hex = /^[0-9a-f]+$/i; var MOCA_REGEXP_number = /^[0-9.,-]+$/; var MOCA_REGEXP_float = /^[0-9.]+$/; var MOCA_REGEXP_cc = /^\d{4}(-| )?\d{4}(-| )?\d{4}(-| )?\d{4}$/; var MOCA_REGEXP_cc_exp = /^\d{2}\/\d{2}$/; var MOCA_REGEXP_date = /^(\d{2})-(\d{2})-(\d{4})$/; var MOCA_REGEXP_time = /^[0-9]+:[0-9]+$/; var MOCA_REGEXP_expiry = /^\d+\s+(week|day|month|year)s?$/i; var MOCA_REGEXP_names = /^[ $a-z0-9_&@()'.,";~-]{0,255}$/i; var MOCA_REGEXP_simple_names = /^[ a-z,0-9"'.-]{0,255}$/i; var MOCA_REGEXP_labels = /^[ $#a-z0-9_&%\/@()'."+!,:;~?>-]{0,255}$/i; var MOCA_REGEXP_data = /^[a-z#?0-9_&%@()-;:,'~".!+\n\r ]{0,1024}$/i; var MOCA_REGEXP_url = /^[a-z=0-9_&@%-:\/;,'".~!+?+]{0,255}$/i; var MOCA_REGEXP_keywords = /^[a-z0-9, '-]+$/i; function MocaForm(fields){ this.fields = fields; // All MocaFields {name:[prop,prop,prop,etc],...} this.values = {}; // Cache of processed element values this.els = {}; // Cache of element refs this.name = ''; // current actual name value this.field = []; // Current MocaField (being validated) this.element = null; // Currently element this.value = ''; // Current element value } MocaForm.prototype = { MJS_T: 'text', // == EL_ID_TEXT MJS_TA: 'textarea', MJS_S: 'select', MJS_RG: 'radio', MJS_C: 'checkbox', MJS_CG: 'checkboxgroup', MJS_D: 'date', MJS_P: 'password', MJS_H: 'hidden', MJS_L: 'label', MJS_DS: 'dateselector', MJS_PH: 'phone', required_if: {}, require:function(fields,preserve){ var flds = fields.splice ? fields : [fields]; if(!preserve){ for(var f in this.fields){ f[MJS_REQUIRED] = false; } } for(var i=0; ithis.field[MJS_TEXT_MAX]){ return this.max_error(); } break; case this.MJS_P: // password req_if_ord = MJS_TEXT_REQ_IF; var val = this.values[f] = this.value = $.trim(this.element.value); if(this.field[MJS_REQUIRED] && !val){ return this.req_error(); } if(val && this.field[MJS_REGEXP]){ if(!this.field[MJS_REGEXP].test(val)){ return this.val_error(); } } if(this.field[MJS_TEXT_MIN] && val && val.lengththis.field[MJS_TEXT_MAX]){ return this.max_error(); } break; case this.MJS_TA: // textarea req_if_ord = MJS_TEXTAREA_REQ_IF; var val = this.values[f] = this.value = $.trim(this.element.value); if(this.field[MJS_REQUIRED] && !val){ return this.req_error(); } if(val && this.field[MJS_REGEXP]){ if(!this.field[MJS_REGEXP].test(val)){ return this.val_error(); } } break; case this.MJS_S: // select req_if_ord = MJS_SEL_REQ_IF; idx = this.element.selectedIndex; if(this.field[MJS_REQUIRED]){ if((idx == -1) || (!idx && this.field[MJS_SEL_IGNORE_FIRST])){ return this.sel_error(); } } this.value = this.values[f] = $('#mf_select_'+f).val(); break; case this.MJS_RG: // radio group if(this.field[MJS_REQUIRED]){ var val = false; var chk = document.getElementsByName('mf_'+ this.MJS_RG + '_' + f ); for (var i = 0; i < chk.length; i++){ if (chk[i].checked) {val = chk[i].value;break;} } if(!val){ this.element = chk; return this.grp_error(); } } break; case this.MJS_CG: // checkbox group if(this.field[MJS_REQUIRED]){ this.values[f] = []; // don't really need these otherwise var chk = document.getElementsByName('mf_'+ this.MJS_CG + '_' + f + '[]'); for (var i = 0; i < chk.length; i++){ if (chk[i].checked) {this.values[f].push(chk[i].value);} } if(!this.values[f].length){ this.element = chk; return this.grp_error(); } } break; case this.MJS_C: // checkbox if(this.element.checked){ this.value = this.values[f] = this.element.value; } else{ if(this.field[MJS_REQUIRED]){ return this.chk_error(); } } break; case this.MJS_D: // date req_if_ord = MJS_DATE_REQ_IF; var val = $.trim(this.element.value); this.values[f] = this.value = val = val.replace(/^\s+|\s+$/g,''); if(val){ if(!MOCA_REGEXP_date.test(val)){return this.val_error();} if(start_date = this.field[MJS_DATE_RANGE_START]){ if(sval = $('#mf_'+ this.field[MJS_TYPE] + '_' + start_date).val()){ var sD,eD; if(bits = MOCA_REGEXP_date.exec(sval)){ sD = new Date(bits[3],bits[2]-1,bits[1]); } if(bits = MOCA_REGEXP_date.exec(val)){ eD = new Date(bits[3],bits[2]-1,bits[1]); } if(sD && eD){ // If not true will get caught above if(sD > eD){ return this.range_error(sD,eD); } } } } } else { if(this.field[MJS_REQUIRED]){return this.chk_error();} } break; case this.MJS_DS: // date selectors var _d = [document.getElementById('mf_'+ this.field[MJS_TYPE] + '_' + f + '_d'), document.getElementById('mf_'+ this.field[MJS_TYPE] + '_' + f + '_m'), document.getElementById('mf_'+ this.field[MJS_TYPE] + '_' + f + '_y')]; this.element = _d[0];// for errors for(i=0; i<_d.length; i++){ idx = _d[i].selectedIndex; if((idx == -1) || (!idx && this.field[MJS_SEL_IGNORE_FIRST])){ if(this.field[MJS_REQUIRED]){return this.dsel_error();} } } this.value = _d.join('-'); break; case this.MJS_PH: // phone boxes var _p = [document.getElementById('mf_'+ this.field[MJS_TYPE] + '_' + f + '_i'), document.getElementById('mf_'+ this.field[MJS_TYPE] + '_' + f + '_a'), document.getElementById('mf_'+ this.field[MJS_TYPE] + '_' + f + '_p')]; this.element = _p[2];// for errors var empty = false; var has_default=false;var vals = []; for(i=0; i<_p.length; i++){ if(v=$.trim(_p[i].value)){ vals.push(v); if(i==0){has_default=true;} } } if(vals.length==1 && has_default && !this.field[MJS_REQUIRED]){ // Just default int code - remove for submission _p.value = ''; break; } if(vals.length==2){return this.ph_error();} if(this.field[MJS_REQUIRED] && (vals.length<3)){return this.req_error();} if(vals.length){ if(!MOCA_REGEXP_integer.test(vals[0])){ this.value = vals[0]; return this.val_error(); } if(!MOCA_REGEXP_integer.test(vals[1])){ this.value = vals[1]; return this.val_error(); } if(!MOCA_REGEXP_phone.test(vals[2])){ this.value = vals[2]; return this.val_error(); } } break; } if(this.field[req_if_ord] && !this.value){ // eg: this.required_if['component_key'] = 'has_component' this.required_if[f] = this.field[req_if_ord]; } } if(this.required_if){ for(var f in this.required_if){ if(this.values[this.required_if[f]]){ this.field = this.fields[f]; this.element = this.els[f]; this.that = this.fields[this.required_if[f]]; return this.req_if_error(); } } } return true; }, req_error:function(){ return this.error('"'+this.field[MJS_NAME] + '" is a required field'); }, val_error:function(){ return this.error('"' + this.value + '" is not a valid value for the "' + this.field[MJS_NAME] + '" field'); }, min_error:function(){ return this.error('Your "' + this.field[MJS_NAME] + '" value must be at least ' + this.field[MJS_TEXT_MIN] + ' characters in length'); }, max_error:function(){ return this.error('Your "' + this.field[MJS_NAME] + '" value must be less than ' + this.field[MJS_TEXT_MAX] + ' characters in length'); }, sel_error:function(){ return this.error('You must select a value from the "' + this.field[MJS_NAME] + '" list to continue'); }, dsel_error:function(){ return this.error('You must select a valid date with the "' + this.field[MJS_NAME] + '" selector to continue'); }, ph_error:function(){ return this.error('Your "' + this.field[MJS_NAME] + '" value must include international and area codes, and the local phone number'); }, grp_error:function(){ return this.error('You must select a value for "' + this.field[MJS_NAME] + '" to continue'); }, chk_error:function(){ return this.error('You must tick the "' + this.field[MJS_NAME] + '" checkbox to continue'); }, req_if_error:function(){ var verbed = this.field[MJS_TYPE]==this.MJS_C || this.field[MJS_TYPE]==this.MJS_S ? 'selected' : 'entered'; return this.error('You must provide a value for ' + this.field[MJS_NAME] + ' if ' + this.that[MJS_NAME] + ' is ' + verbed); }, range_error:function(s,e){ return this.error('You have entered an invalid date range:
('+s.mocaToString() + ' to '+e.mocaToString()+')',true); }, error:function(str,no_focus){ if(this.field[MJS_TYPE] != this.MJS_RG && this.field[MJS_TYPE] != this.MJS_CG){ var bg = this.element.style.backgroundColor; this.element.style.backgroundColor = MJS_COLOUR_ERROR; var revert = function(){this.style.backgroundColor=bg;}; this.element.onclick = revert; this.element.onkeydown = revert; no_focus || this.element.focus(); } bootbox.alert(str); } }; function formError(el_id,msg,no_focus){ // formError('element_id','error_msg' [, 'title', 'functionOnDismiss']); // Class function - first arg must be element_id, // second is alert message, third is alert title, // fourth is function to be executed on alert // dismissal. Only the first two are mandatory var title = arguments[2] ? arguments[2] : ''; var func = arguments[3] ? arguments[3] : null; var el = document.getElementById(el_id); var bg = el.style.backgroundColor; el.style.backgroundColor = MJS_COLOUR_ERROR; var revert = function(){this.style.backgroundColor=bg;}; el.onclick = revert; el.onkeydown = revert; no_focus || el.focus(); mocaAlert(msg,title,func); return false; }