| dojo.provide("tapestry.form"); |
| dojo.provide("tapestry.form.datetime"); |
| dojo.provide("tapestry.form.validation"); |
| dojo.provide("tapestry.form_compat"); |
| dojo.provide("Tapestry"); |
| |
| dojo.require("dojo.event.browser"); |
| dojo.require("dojo.dom"); |
| dojo.require("dojo.html.selection"); |
| dojo.require("tapestry.core"); |
| dojo.require("dojo.date.format"); |
| dojo.require("dojo.validate.datetime"); |
| dojo.require("dojo.validate.check"); |
| dojo.require("dojo.html.style"); |
| |
| /** |
| * package: tapestry.form |
| * Provides central handling of all client side form related logic. |
| */ |
| tapestry.form={ |
| |
| // property: forms |
| // Contains a reference to all registered Tapestry forms in the current document. |
| forms:{}, // registered form references |
| // property: currentFocus |
| // Reference to form element/element id of field that should currently recieve focus, if any |
| currentFocus:null, |
| |
| /** |
| * Function: focusField |
| * If possible, brings keyboard input focus to the specified field. |
| * |
| * Parameters: |
| * field - The field(field id) of the field to focus. |
| * |
| * Note: |
| * Function deprecated in favor of dojo equivalent, like |
| * dojo.html.selectInputText(node). |
| */ |
| focusField:function(field){ |
| if (arguments.length < 1) {return;} |
| |
| var f=dojo.widget.byId(field); |
| if(f && !dj_undef("focus", f)){ |
| if (dojo.html.isVisible(f)){ |
| f.focus(); |
| } |
| return; |
| } else { |
| f = dojo.byId(field); |
| } |
| |
| if (!f) { return; } |
| if (field.disabled || field.clientWidth < 1) { |
| return; |
| } |
| |
| if(!dj_undef("focus", f) && dojo.html.isShowing(f)){ |
| f.focus(); |
| return; |
| } |
| |
| dojo.html.selectInputText(field); |
| }, |
| |
| /** |
| * Used by AlertDialog to focus the highest priority form field |
| * that failed validation. This happens because the field needs to |
| * be focused ~after~ the dialog is hidden. |
| */ |
| _focusCurrentField:function(){ |
| if(!this.currentFocus){return;} |
| |
| this.focusField(this.currentFocus); |
| }, |
| |
| /** |
| * Function: registerForm |
| * |
| * Registers the form with the local <forms> property so |
| * that there is a central reference of all tapestry forms. |
| * |
| * Parameters: |
| * |
| * id - The form(form id) to register. |
| * async - Boolean, if true causes form submission to be asynchronous. |
| * json - Boolean, if true causes form submission to be asyncrhronous with an |
| * expected JSON response. |
| */ |
| registerForm:function(id, async, json){ |
| var form=dojo.byId(id); |
| if (!form) { |
| dojo.raise("Form not found with id " + id); |
| return; |
| } |
| |
| // make sure id is correct just in case node passed in has only name |
| id=form.getAttribute("id"); |
| |
| // if previously connected, cleanup and reconnect |
| if (this.forms[id]) { |
| dojo.event.disconnect(form, "onsubmit", this, "onFormSubmit"); |
| for(var i = 0; i < form.elements.length; i++) { |
| var node = form.elements[i]; |
| if(node && node.type && dojo.lang.inArray(["submit", "button"],node.type.toLowerCase())) { |
| dojo.event.disconnect(node, "onclick", tapestry.form, "inputClicked"); |
| } |
| } |
| |
| var inputs = form.getElementsByTagName("input"); |
| for(var i = 0; i < inputs.length; i++) { |
| var input = inputs[i]; |
| if(input.type.toLowerCase() == "image" && input.form == form) { |
| dojo.event.disconnect(input, "onclick", tapestry.form, "inputClicked"); |
| } |
| } |
| |
| dojo.event.disconnect(form, "onsubmit", this, "overrideSubmit"); |
| delete this.forms[id]; |
| } |
| |
| this.forms[id]={}; |
| this.forms[id].validateForm=true; |
| this.forms[id].profiles=[]; |
| this.forms[id].async=(typeof async != "undefined") ? async : false; |
| this.forms[id].json=(typeof json != "undefined") ? json : false; |
| |
| if (!this.forms[id].async) { |
| dojo.event.connect(form, "onsubmit", this, "onFormSubmit"); |
| } else { |
| for(var i = 0; i < form.elements.length; i++) { |
| var node = form.elements[i]; |
| if(node && node.type && dojo.lang.inArray(["submit", "button"],node.type.toLowerCase())) { |
| dojo.event.connect(node, "onclick", tapestry.form, "inputClicked"); |
| } |
| } |
| |
| var inputs = form.getElementsByTagName("input"); |
| for(var i = 0; i < inputs.length; i++) { |
| var input = inputs[i]; |
| if(input.type.toLowerCase() == "image" && input.form == form) { |
| dojo.event.connect(input, "onclick", tapestry.form, "inputClicked"); |
| } |
| } |
| |
| dojo.event.connect(form, "onsubmit", this, "overrideSubmit"); |
| } |
| }, |
| |
| overrideSubmit:function(e){ |
| dojo.event.browser.stopEvent(e); |
| var elm = e.target; |
| if (!dj_undef("form", elm)){ |
| dojo.log.debug("Submit event was generated from element: ", elm); |
| elm = elm.form; |
| } |
| tapestry.form.submitAsync(elm); |
| }, |
| |
| /** |
| * Function: registerProfile |
| * |
| * Registers a form validation/translation profile. There |
| * can potentially be more than one profile registered with |
| * a form. |
| * |
| * The profiles will be consulted at various points in the forms |
| * life, which currently only involves running the profile checks |
| * before form submission. (more points to be determined in the future) |
| * |
| * See Also: |
| * <dojo.validate.check> |
| * |
| * Parameters: |
| * |
| * id - The form(form id) to register profile with. |
| * profile - The object containing all of the validation/value constraints for the form. |
| */ |
| registerProfile:function(id, profile){ |
| if (!this.forms[id]) { |
| dojo.raise("registerProfile(" + id + ") No form previously registered with that id."); |
| return; |
| } |
| |
| this.forms[id].profiles.push(profile); |
| }, |
| |
| /** |
| * Function: clearProfiles |
| * |
| * Clears any previously registered validation profiles |
| * on the specified form. Normally called during XHR requests |
| * by returned JS response to ensure new validation logic coming |
| * in from potentially new form fields is accounted for. |
| * |
| * Parameters: |
| * |
| * id - The form id to clear profiles for. |
| */ |
| clearProfiles:function(id){ |
| if (!this.forms[id]) return; |
| |
| for (var i=0; i < this.forms[id].profiles.length; i++) { |
| delete this.forms[id].profiles[i]; |
| } |
| this.forms[id].profiles=[]; |
| }, |
| |
| inputClicked:function(e){ |
| var node = e.currentTarget; |
| if(node.disabled || dj_undef("form", node)) { return; } |
| this.forms[node.form.getAttribute("id")].clickedButton = node; |
| }, |
| |
| /** |
| * Function: setFormValidating |
| * |
| * If a form registered with the specified formId |
| * exists a local property will be set that causes |
| * validation to be turned on/off depending on the argument. |
| * |
| * Parameters: |
| * |
| * formId - The id of the form to turn validation on/off for. |
| * validate - Boolean for whether or not to validate form, if not specified assumes true. |
| */ |
| setFormValidating:function(formId, validate){ |
| if (this.forms[formId]){ |
| this.forms[formId].validateForm = validate; |
| } |
| }, |
| |
| /** |
| * Event connected function that is invoked when a form |
| * is submitted. |
| */ |
| onFormSubmit:function(evt){ |
| if(!evt || dj_undef("target", evt)) { |
| dojo.raise("No valid form event found with argument: " + evt); |
| return; |
| } |
| |
| var id=evt.target.getAttribute("id"); |
| if (!id) { |
| dojo.raise("Form had no id attribute."); |
| return; |
| } |
| var form = dojo.byId(id); |
| |
| if (!dj_undef("value", form.submitmode) |
| && (form.submitmode.value == "cancel" || form.submitmode.value == "refresh")) { |
| return; |
| } |
| |
| if (!tapestry.form.validation.validateForm(form, this.forms[id])) { |
| dojo.event.browser.stopEvent(evt); |
| } |
| }, |
| |
| /** |
| * Function: submit |
| * |
| * Submits the form specified, optionally setting the submitname |
| * hidden input field to the value of submitName to let the Form |
| * component on server know which button caused the submission. (For |
| * the case of submit button listeners). |
| * |
| * Parameters: |
| * |
| * form - The form(form id) to submit. |
| * submitName - Optional submit name string to use when submitting. This is used |
| * to associate a form submission with a particular component, like a |
| * Submit/LinkSubmit/etc.. |
| * parms - Optional extra set of arguments that can control the form submission semantics |
| * such as url/async/json/etc. |
| */ |
| submit:function(form, submitName, parms){ |
| form=dojo.byId(form); |
| if (!form) { |
| dojo.raise("Form not found with id " + form); |
| return; |
| } |
| var id=form.getAttribute("id"); |
| if (submitName){ |
| form.submitname.value=submitName; |
| } |
| |
| if (!dj_undef("value", form.submitmode) |
| && (form.submitmode.value == "cancel" || form.submitmode.value == "refresh") |
| && !parms) { |
| form.submit(); |
| return; |
| } |
| |
| if (!tapestry.form.validation.validateForm(form, this.forms[id])) { |
| return; |
| } |
| |
| if (parms && !dj_undef("async", parms) && parms.async) { |
| tapestry.form.submitAsync(form, null, submitName, parms); |
| return; |
| } else if(!dj_undef(id, this.forms) && this.forms[id].async){ |
| tapestry.form.submitAsync(form); |
| return; |
| } |
| |
| form.submit(); |
| }, |
| |
| /** |
| * Function: cancel |
| * |
| * Submits the form to the server in "cancel" mode, invoking any cancel listeners |
| * registered to the server side equivalent to the form passed in. |
| * |
| * Parameters: |
| * |
| * form - The form(form id) to cancel. |
| * submitName - Optional submit name string to use when submitting. This is used |
| * to associate a form submission with a particular component, like a |
| * Submit/LinkSubmit/etc.. |
| * parms - Optional object parms passed through to tapestry.form.submit(). |
| */ |
| cancel:function(form, submitName, parms){ |
| form=dojo.byId(form); |
| if (!form){ |
| dojo.raise("Form not found with id " + form); |
| return; |
| } |
| |
| var formName=form.getAttribute("id"); |
| var validateState=tapestry.form.forms[formName].validateForm; |
| tapestry.form.setFormValidating(formName, false); |
| |
| form.submitmode.value="cancel"; |
| |
| if (parms && !dj_undef("async", parms) && parms.async){ |
| this.submitAsync(form, null, submitName, parms); |
| } else { |
| this.submit(form, submitName, parms); |
| } |
| |
| tapestry.form.setFormValidating(formName, validateState); |
| }, |
| |
| /** |
| * Function: refresh |
| * |
| * Submits the form to the server in "refresh" mode, invoking any refresh listeners |
| * registered to the server side equivalent to the form passed in. |
| * |
| * Parameters: |
| * |
| * form - The form(form id) to refresh. |
| * submitName - Optional submit name string to use when submitting. This is used |
| * to associate a form submission with a particular component, like a |
| * Submit/LinkSubmit/etc.. |
| * parms - Optional object parms passed through to tapestry.form.submit(). |
| */ |
| refresh:function(form, submitName, parms){ |
| form=dojo.byId(form); |
| if (!form){ |
| dojo.raise("Form not found with id " + form); |
| return; |
| } |
| |
| var formName=form.getAttribute("id"); |
| var validateState=tapestry.form.forms[formName].validateForm; |
| tapestry.form.setFormValidating(formName, false); |
| |
| form.submitmode.value="refresh"; |
| |
| if (parms && !dj_undef("async", parms) && parms.async){ |
| this.submitAsync(form, null, submitName, parms); |
| } else { |
| this.submit(form, submitName, parms); |
| } |
| |
| tapestry.form.setFormValidating(formName, validateState); |
| }, |
| |
| /** |
| * Function: submitAsync |
| * |
| * Does almost the same thing as <tapestry.form.submit>, |
| * but submits the request via XHR to the server asynchronously. |
| * |
| * Parameters: |
| * |
| * form - The form(form id) to submit. |
| * content - Optional content map, mainly used to pass in browser |
| * event parameters to form submission, but can be any |
| * typical form/value pair. |
| * submitName - Optional submit name string to use when submitting. |
| * parms - Optional set of extra parms that can override the defautls for |
| * this specific form submission, like the url/async/json behaviour of |
| * the submission. |
| */ |
| submitAsync:function(form, content, submitName, parms){ |
| form=dojo.byId(form); |
| if (!form) { |
| dojo.raise("Form not found with id " + id); |
| return; |
| } |
| var formId=form.getAttribute("id"); |
| |
| if (!tapestry.form.validation.validateForm(form, this.forms[formId])) { |
| dojo.log.debug("Form validation failed for form with id " + formId); |
| return; |
| } |
| |
| if (submitName){ |
| form.submitname.value=submitName; |
| if(!content){ content={}; } |
| if(form[submitName]){ |
| content[submitName]=form[submitName].value; |
| } |
| } |
| |
| // handle submissions from input buttons |
| if (!dj_undef("clickedButton", this.forms[formId])) { |
| if (!content) { content={}; } |
| content[this.forms[formId].clickedButton.getAttribute("name")]=this.forms[formId].clickedButton.getAttribute("value"); |
| } |
| |
| var kwArgs={ |
| formNode:form, |
| content:content, |
| useCache:true, |
| preventCache:true, |
| error: (function(){tapestry.error.apply(this, arguments);}), |
| encoding: tapestry.requestEncoding |
| }; |
| |
| // check for override |
| if (parms){ |
| if (!dj_undef("url", parms)) { kwArgs.url=parms.url; } |
| } |
| |
| if (this.forms[formId].json || parms && parms.json) { |
| kwArgs.headers={"json":true}; |
| kwArgs.mimetype="text/json"; |
| kwArgs.load=(function(){tapestry.loadJson.apply(this, arguments);}); |
| } else { |
| kwArgs.headers={"dojo-ajax-request":true}; |
| kwArgs.mimetype="text/xml"; |
| kwArgs.load=(function(){tapestry.load.apply(this, arguments);}); |
| } |
| tapestry.requestsInFlight++; |
| dojo.io.queueBind(kwArgs); |
| } |
| } |
| |
| tapestry.form.validation={ |
| |
| missingClass:"fieldMissing", // default css class that will be applied to fields missing a value |
| invalidClass:"fieldInvalid", // default css class applied to fields with invalid data |
| |
| dialogName:"tapestry:AlertDialog", |
| |
| /** |
| * Main entry point for running form validation. The |
| * props object passed in contains a number of fields that |
| * are managed by tapestry.form: |
| * |
| * props = { |
| * validateForm:[true|false] // whether to run validation at all |
| * profiles:[profile1, profile2] // set of dojo.validate.check() style profiles |
| * // that may have been registered with form |
| * } |
| * |
| * The individual profiles will contain any of the data described by the dojo documentation |
| * for dojo.validate.check(). In addition to that, each profile will also have a corresponding |
| * string message to display if the specified condition has been met. For example, if you have |
| * specified that a select field named "select1" was required your profile would look something |
| * like: |
| * |
| * profile = { |
| * "required":["select1"], // normal dojo.validate.check data |
| * "select1":{ // tapestry field/error type specific data |
| * "required":"You must select a value for select1." |
| * } |
| * } |
| * |
| * It is intended for you to call dojo.validate.check(form, profile) for each profile |
| * stored in the "profiles" field, as well as deciding how to display errors / warnings. |
| * |
| * @return Boolean indicating if form submission should continue. If false the form |
| * will ~not~ be submitted. |
| */ |
| validateForm:function(form, props){ |
| if (typeof form == "undefined") {return false;} |
| if (typeof props == "undefined") {return true;} // form exists but no profile? just submit I guess.. |
| if (!props.validateForm) {return true;} |
| |
| try { |
| this.clearValidationDecorations(form, props); |
| |
| for (var i=0; i < props.profiles.length; i++) { |
| var results=dojo.validate.check(form, props.profiles[i]); |
| |
| if (!this.processResults(form, results, props.profiles[i])) { |
| this.summarizeErrors(form, results, props.profiles[i]); |
| return false; |
| } |
| } |
| } catch (e) { |
| // since so many dynamic function calls may happen in here it's best that we |
| // catch all of them and log them or else peoples forms might still get submitted |
| // and they'd never be able to figure out what was wrong |
| dojo.log.exception("Error validating", e, true); |
| return false; |
| } |
| |
| return true; |
| }, |
| |
| /** |
| * Called for each registered profile on a form after |
| * dojo.validate.check() has been called. This function is |
| * expected to do UI related notifications of fields in error. |
| * |
| * @param form The form that was validated. |
| * @param results The result of calling dojo.validate.check(form,profile) |
| * @param profile The original profile used to validate form, also holds |
| * validation error messages to be used for each field. |
| * |
| * @return Boolean, if false form should not be submitted and all validation |
| * should be stopped. If true validation will continue and eventually |
| * form will be submitted. |
| */ |
| processResults:function(form, results, profile){ |
| if (results.isSuccessful()) { return true; } |
| |
| var formValid=true; |
| if (results.hasMissing()) { |
| var missing=results.getMissing(); |
| for (var i=0; i < missing.length; i++) { |
| this.handleMissingField(missing[i], profile); |
| } |
| |
| formValid=false; |
| } |
| |
| if (results.hasInvalid()) { |
| var invalid=results.getInvalid(); |
| for (var i=0; i < invalid.length; i++) { |
| this.handleInvalidField(invalid[i], profile); |
| } |
| |
| formValid=false; |
| } |
| |
| return formValid; // if got past successful everything is invalid |
| }, |
| |
| /** |
| * Default field decorator for missing fields. |
| * |
| * @param field The field element that was missing data. |
| * @param profile The form validation profile. |
| */ |
| handleMissingField:function(field, profile){ |
| field=dojo.byId(field); |
| if (dj_undef("type", field)) {return;} |
| dojo.html.removeClass(field, this.invalidClass); |
| |
| if (!dojo.html.hasClass(field, this.missingClass)){ |
| dojo.html.prependClass(field, this.missingClass); |
| } |
| }, |
| |
| /** |
| * Default field decorator for invalid fields. |
| * |
| * @param field The field element that had invalid data. |
| * @param profile The form validation profile. |
| */ |
| handleInvalidField:function(field, profile){ |
| field=dojo.byId(field); |
| if (dj_undef("type", field)) {return;} |
| dojo.html.removeClass(field, this.missingClass); |
| |
| if (!dojo.html.hasClass(field, this.invalidClass)){ |
| dojo.html.prependClass(field, this.invalidClass); |
| } |
| }, |
| |
| /** |
| * Clears out previous css classes set on fields |
| * in error. |
| */ |
| clearValidationDecorations:function(form, props){ |
| |
| for (var i=0; i < props.profiles.length; i++) { |
| |
| for (var fieldName in props.profiles[i]) { |
| if (dj_undef("type", form.elements[fieldName]) || typeof form.elements[fieldName].type == "undefined" |
| || form.elements[fieldName].type == "submit" |
| || form.elements[fieldName].type == "hidden") { continue; } |
| |
| dojo.html.removeClass(form.elements[fieldName], this.missingClass); |
| dojo.html.removeClass(form.elements[fieldName], this.invalidClass); |
| } |
| } |
| }, |
| |
| /** |
| * Optionally allows an alert dialog/dhtml dialog/etc to |
| * be displayed to user to alert them to the invalid state |
| * of their form if validation errors have occurred. |
| * |
| * @param form The form being validated. |
| * @param results Returned value of dojo.validate.check(form, profile) |
| * @param profile Validation profile definition |
| */ |
| summarizeErrors:function(form, results, profile){ |
| var merrs=[]; |
| var ierrs=[]; |
| tapestry.form.currentFocus=null; |
| |
| if (results.hasMissing()){ |
| var fields=results.getMissing(); |
| for (var i=0; i<fields.length; i++){ |
| if(i==0 && !tapestry.form.currentFocus){ |
| tapestry.form.currentFocus=fields[i]; |
| } |
| if (profile[fields[i]] && profile[fields[i]]["required"]){ |
| if (dojo.lang.isArray(profile[fields[i]]["required"])) { |
| for (var z=0; z < profile[fields[i]]["required"].length; z++) |
| merrs.push(profile[fields[i]]["required"][z]); |
| } else |
| merrs.push(profile[fields[i]]["required"]); |
| } |
| } |
| } |
| if (results.hasInvalid()){ |
| var fields=results.getInvalid(); |
| for (var i=0; i<fields.length; i++){ |
| if(i==0 && !tapestry.form.currentFocus){ |
| tapestry.form.currentFocus=fields[i]; |
| } |
| if (profile[fields[i]] && profile[fields[i]]["constraints"]){ |
| if (dojo.lang.isArray(profile[fields[i]]["constraints"])) { |
| for (var z=0; z < profile[fields[i]]["constraints"].length; z++) |
| ierrs.push(profile[fields[i]]["constraints"][z]); |
| } else |
| ierrs.push(profile[fields[i]]["constraints"]); |
| } |
| } |
| } |
| |
| var msg=""; |
| if (merrs.length > 0) { |
| msg+='<ul class="missingList">'; |
| for (var i=0; i<merrs.length;i++) { |
| msg+="<li>"+merrs[i]+"</li>"; |
| } |
| msg+="</ul>"; |
| } |
| if (ierrs.length > 0) { |
| msg+='<ul class="invalidList">'; |
| for (var i=0; i<ierrs.length;i++) { |
| msg+="<li>"+ierrs[i]+"</li>"; |
| } |
| msg+="</ul>"; |
| } |
| |
| dojo.require("dojo.widget.*"); |
| dojo.require("tapestry.widget.AlertDialog"); |
| |
| var ad=dojo.widget.byId("validationDialog"); |
| if (ad) { |
| ad.setMessage(msg); |
| ad.show(); |
| return; |
| } |
| |
| var node=document.createElement("span"); |
| document.body.appendChild(node); |
| var dialog=dojo.widget.createWidget(this.dialogName, |
| { |
| widgetId:"validationDialog", |
| message:msg |
| }, node); |
| dialog.show(); |
| }, |
| |
| /** |
| * Validates that the input value matches the given |
| * regexp pattern. |
| * |
| * @param value The string value to be evaluated. |
| * @param pattern The regexp pattern used to match against value. |
| */ |
| isValidPattern:function(value, pattern){ |
| if (typeof value != "string" || typeof pattern != "string") { return false; } |
| |
| var re = new RegExp(pattern); |
| return re.test(value); |
| }, |
| |
| isPalleteSelected:function(elem){ |
| return elem.length > 0; |
| }, |
| |
| /** |
| * Validates that the input value is equal with the value of the given input control. |
| */ |
| isEqual:function(value, other){ |
| var otherValue = dojo.byId(other).value; |
| return value == otherValue; |
| }, |
| |
| /** |
| * Validates that the input value is not equal with the value of the given input control. |
| */ |
| isNotEqual:function(value, other){ |
| return !tapestry.form.validation.isEqual(value, other); |
| }, |
| |
| /** |
| * Checks that the value given is greater than or equal to the value of |
| * minString. Uses dojo.i18n.number.parse() to parse out the values using |
| * the locale settings configured for the current page. |
| */ |
| greaterThanOrEqual:function(value, minString, flags){ |
| flags.validate=false; |
| var min = dojo.i18n.number.parse(minString, null, flags); |
| var num = dojo.i18n.number.parse(value, null, flags); |
| if (Number.NaN == num) { return false; } |
| |
| return num >= min; |
| }, |
| |
| /** |
| * Checks that the value given is less than or equal to the value of |
| * maxString. Uses dojo.i18n.number.parse() to parse out the values using |
| * the locale settings configured for the current page. |
| */ |
| lessThanOrEqual:function(value, maxString, flags){ |
| flags.validate=false; |
| var max = dojo.i18n.number.parse(maxString, null, flags); |
| var num = dojo.i18n.number.parse(value, null, flags); |
| if (Number.NaN == num) { return false; } |
| |
| return num <= max; |
| } |
| } |
| |
| tapestry.form.datetime={ |
| |
| /** |
| * Checks if the specified value is a valid date, according to |
| * the flags passed in. |
| * |
| * @param value The string value of the date being validated. |
| * @param flags An object. |
| * flags.format A string format pattern that will be used to validate |
| * the incoming value via @link dojo.validate.isValidDate(value, format). |
| * flags.max A string date value representing the maximum date that can be selected. |
| * flags.min A string date value representing the minimum date that can be selected. |
| * @return Boolean. True if valid, false otherwise. |
| */ |
| isValidDate:function(value, flags){ |
| if(!value){return false;} |
| |
| if (!flags){ |
| dojo.raise("isValidDate: value and flags must be specified"); |
| return; |
| } |
| |
| // parse date value |
| var dateValue=null; |
| try { |
| dateValue = dojo.date.parse(value, flags); |
| } catch (e) { |
| dojo.log.exception("Error parsing input date.", e, true); |
| return false; |
| } |
| |
| if(dateValue == null) { return false; } |
| |
| // convert to format that is validatable |
| value=dojo.date.format(dateValue, flags); |
| |
| // TODO: This is totally useless right now, doesn't even accept formats with string equivs |
| // See a better method http://www.mattkruse.com/javascript/date/source.html |
| // basic format validation |
| // if (!dojo.validate.isValidDate(value, flags.format)) |
| // return false; |
| |
| // max date |
| if (!dj_undef("max", flags)){ |
| if (typeof flags.max == "string"){ |
| flags.max=dojo.date.parse(flags.max, flags); |
| } |
| if (dojo.date.compare(dateValue, flags.max, dojo.date.compareTypes.DATE) > 0) |
| return false; |
| } |
| |
| // min date |
| if (!dj_undef("min", flags)){ |
| if (typeof flags.min == "string"){ |
| flags.min=dojo.date.parse(flags.min, flags); |
| } |
| if (dojo.date.compare(dateValue, flags.min, dojo.date.compareTypes.DATE) < 0) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } |
| |
| // package: tapestry.form_compat |
| // Backwards compatibility functions, to be removed in 4.1.1 js version. Contains all of |
| // the functions found in the old Form.js provided by previous Tapestry releases. |
| // Should only be included by tapestry.form, don't dojo.require() this module. |
| |
| // global used to deprecate old event connection methods |
| tapestry.form.deprecateConnect=function(formName, fnc, event, advice){ |
| dojo.deprecated("Tapestry.on"+event, |
| "use dojo.event.connect instead", |
| "4.1.1"); |
| |
| if (advice) { |
| dojo.event.connect(advice, dojo.byId(formName), event, fnc); |
| } else { |
| dojo.event.connect(dojo.byId(formName), event, fnc); |
| } |
| } |
| |
| // BEGIN old function definitions |
| |
| Tapestry.default_invalid_field_handler=function(event, field, message){ |
| dojo.deprecated("Tapestry.default_invalid_field_handler", |
| "use tapestry.form.validation.validateForm instead", |
| "4.1.1"); |
| if (field.disabled) return; |
| |
| if (typeof window != "undefined"){ |
| window.alert(message); |
| } else { |
| dojo.debug("Invalid field : " + message); |
| } |
| tapestry.form.focusField(field); |
| } |
| |
| Tapestry.invalid_field=function(field, message){ |
| Tapestry.default_invalid_field_handler(null, field, message); |
| } |
| |
| Tapestry.find=function(id){ |
| dojo.deprecated("Tapestry.find", |
| "use dojo.byId instead", |
| "4.1.1"); |
| return dojo.byId(id); |
| } |
| |
| Tapestry.register_form=function(formId){ |
| dojo.deprecated("Tapestry.register_form", |
| "use tapestry.form.registerForm instead register_form(" + formId + ")", |
| "4.1.1"); |
| tapestry.form.registerForm(formId); |
| } |
| |
| Tapestry.onpresubmit=function(formName, fnc){ tapestry.form.deprecateConnect(formName, fnc, "onsubmit", "before"); }; |
| Tapestry.onsubmit=function(formName, fnc){ tapestry.form.deprecateConnect(formName, fnc, "onsubmit"); }; |
| Tapestry.onpostsubmit=function(formName, fnc){ tapestry.form.deprecateConnect(formName, fnc, "onsubmit", "after"); }; |
| Tapestry.onreset=function(formName, fnc){ tapestry.form.deprecateConnect(formName, fnc, "onreset"); }; |
| Tapestry.onrefresh=function(formName, fnc){ tapestry.form.deprecateConnect(formName, fnc, "onrefresh"); }; |
| Tapestry.oncancel=function(formName, fnc){ tapestry.form.deprecateConnect(formName, fnc, "oncancel"); }; |
| |
| Tapestry.set_focus=function (field){ |
| dojo.deprecated("Tapestry.set_focus", |
| "use tapestry.form.focusField instead", |
| "4.1.1"); |
| tapestry.form.focusField(field); |
| } |
| |
| Tapestry.trim_field_value = function(fieldId) |
| { |
| dojo.deprecated("Tapestry.trim_field_value", |
| "use dojo.html instead", |
| "4.1.1"); |
| |
| if (arguments.length < 1) return; |
| |
| var elm=dojo.byId(id); |
| if (!elm) {return;} |
| if ( elm.type != "text" && elm.type != "textarea" |
| && elm.type != "password" ) { return; } |
| |
| elm.value = elm.value.replace(/(^\s*|\s*$)/g, ""); |
| } |
| |
| Tapestry.require_field = function(event, field, message) |
| { |
| dojo.deprecated("Tapestry.require_field", |
| "use tapestry.form.validation.validateForm instead", |
| "4.1.1"); |
| if (arguments.length < 1) return; |
| |
| var elem=dojo.byId(field); |
| if (!elem) { return; } |
| |
| // Are textbox, textarea, or password fields blank. |
| if ( (elem.type == "text" || elem.type == "textarea" || elem.type == "password") |
| && /^\s*$/.test(elem.value) ) { |
| Tapestry.default_invalid_field_handler(elem, message); |
| return; |
| } |
| // Does drop-down box have option selected. |
| else if ( (elem.type == "select-one" || elem.type == "select-multiple") |
| && elem.selectedIndex == -1 ) { |
| Tapestry.default_invalid_field_handler(elem, message); |
| return; |
| } else if ( elem instanceof Array ) { |
| // Does radio button group (or check box group) have option checked. |
| var checked = false; |
| for (var j = 0; j < elem.length; j++) { |
| if (elem[j].checked) { checked = true; } |
| } |
| if ( !checked ) { |
| Tapestry.default_invalid_field_handler(elem, message); |
| return; |
| } |
| } |
| } |
| |
| Tapestry.submit_form = function(form_id, field_name) |
| { |
| dojo.deprecated("Tapestry.submit_form", |
| "use tapestry.form.submit instead (" + form_id + ", " + field_name + ")", |
| "4.1.1"); |
| tapestry.form.submit(form_id, field_name); |
| } |