1// Ensure Alfresco.forms and validation objects exist 2Alfresco.forms = Alfresco.forms || {}; 3Alfresco.forms.validation = Alfresco.forms.validation || {}; 4 5/** 6 * Class to represent the forms runtime. 7 * 8 * @namespace Alfresco.forms 9 * @class Alfresco.forms.Form 10 */ 11(function() 12{ 13 /** 14 * YUI Library aliases 15 */ 16 var Dom = YAHOO.util.Dom, 17 Event = YAHOO.util.Event, 18 Selector = YAHOO.util.Selector, 19 KeyListener = YAHOO.util.KeyListener; 20 21 /** 22 * Constructor for a form. 23 * 24 * @param {String} formId The HTML id of the form to be managed 25 * @return {Alfresco.forms.Form} The new Form instance 26 * @constructor 27 */ 28 Alfresco.forms.Form = function(formId) 29 { 30 this.formId = formId; 31 this.showSubmitStateDynamically = false; 32 this.reusable = true; 33 this.submitAsJSON = false; 34 this.submitElements = []; 35 this.validations = []; 36 this.tooltips = {}; 37 this._valid = null; 38 this._fieldEvents = {}; 39 this._visitedFields = {}; 40 this.ajaxSubmit = false; 41 this.ajaxSubmitMethod = "POST"; 42 this.ajaxNoReloadOnAuthFailure = null; 43 this.errorContainer = "tooltip"; 44 this.showMultipleErrors = true; 45 46 // Make sure to hide error containers (i.e. tooltips) when overlays and panels are closed 47 48 YAHOO.Bubbling.on("showPanel", this.hideErrorContainer, this); 49 YAHOO.Bubbling.on("hidePanel", this.hideErrorContainer, this); 50 YAHOO.Bubbling.on("showOverlay", this.hideErrorContainer, this); 51 YAHOO.Bubbling.on("hideOverlay", this.hideErrorContainer, this); 52 53 return this; 54 }; 55 56 YAHOO.lang.augmentObject(Alfresco.forms.Form, 57 { 58 NOTIFICATION_LEVEL_NONE: 1, 59 60 /** 61 * Applies css classes against the fields 62 */ 63 NOTIFICATION_LEVEL_FIELD: 2, 64 65 /** 66 * Invokes the error containers 67 */ 68 NOTIFICATION_LEVEL_CONTAINER: 3 69 }); 70 71 Alfresco.forms.Form.prototype = 72 { 73 74 /** 75 * HTML id of the form being represented. 76 * 77 * @property formId 78 * @type string 79 */ 80 formId: null, 81 82 /** 83 * List of ids and/or elements being used to submit the form. 84 * 85 * @property submitElements 86 * @type object[] 87 */ 88 submitElements: null, 89 90 /** 91 * Flag to determine whether the submit elements dynamically update 92 * their state depending on the current values in the form. 93 * 94 * @property showSubmitStateDynamically 95 * @type boolean 96 */ 97 showSubmitStateDynamically: null, 98 99 /** 100 * Flag to determine whether the submit elements shall be enabled again after a successful form submission. 101 * 102 * @property reusable 103 * @type boolean 104 * @default false 105 */ 106 reusable: false, 107 108 /** 109 * Flag to determine whether the form will be submitted using an AJAX request. 110 * 111 * @property ajaxSubmit 112 * @type boolean 113 */ 114 ajaxSubmit: null, 115 116 /** 117 * String representing where errors should be displayed. 118 * If the value is not "alert" it's presumed the string is the id of an 119 * HTML object to be used as the error container. 120 * 121 * @property errorContainer 122 * @type string 123 */ 124 errorContainer: null, 125 126 /** 127 * Boolean deciding if on eor many errors shall be displayed at a time. 128 * 129 * @property showMultipleErrors 130 * @type boolean 131 */ 132 showMultipleErrors: false, 133 134 /** 135 * Object literal containing the abstract function for pre-submission form processing. 136 * fn: function, // The override function. 137 * obj: object, // An object to pass back to the function. 138 * scope: object // The object to use for the scope of the function. 139 * 140 * @property doBeforeFormSubmit 141 * @type object 142 */ 143 doBeforeFormSubmit: 144 { 145 fn: function(form, obj){}, 146 obj: null, 147 scope: this 148 }, 149 150 /** 151 * Object literal containing the abstract function for intercepting AJAX form submission. 152 * Returning false from the override will prevent the Forms Runtime from submitting the data. 153 * fn: function, // The override function. 154 * obj: object, // An object to pass back to the function. 155 * scope: object // The object to use for the scope of the function. 156 * 157 * @property doBeforeAjaxRequest 158 * @type object 159 */ 160 doBeforeAjaxRequest: 161 { 162 fn: function(form, obj) 163 { 164 return true; 165 }, 166 obj: null, 167 scope: this 168 }, 169 170 /** 171 * Object holding the callback handlers and messages for AJAX submissions. 172 * The callback handlers are themselves an object of the form: 173 * fn: function, // The handler to call when the event fires. 174 * obj: object, // An object to pass back to the handler. 175 * scope: object // The object to use for the scope of the handler. 176 * 177 * @property ajaxSubmitHandlers 178 * @type object 179 */ 180 ajaxSubmitHandlers: null, 181 182 /** 183 * String representing the http method to be used for the 184 * ajax call. Default is POST. 185 * 186 * @property ajaxSubmitMethod
187 * @type String 188 */ 189 ajaxSubmitMethod: null, 190 191 /** 192 * Decides if the browser shall try and reload the current page if a form submission fails due to auth failure. 193 * 194 * Possible values: 195 * true - browser will NOT reload current page 196 * false - browser will reload current page 197 * null - Will use the default value of noReloadOnAuthFailure in Alfresco.util.Ajax.request 198 * 199 * @property ajaxNoReloadOnAuthFailure 200 * @type String 201 * @default null 202 */ 203 ajaxNoReloadOnAuthFailure: null, 204 205 /** 206 * Flag to determine whether the form data should be submitted 207 * represented by a JSON structure. 208 * 209 * @property submitAsJSON 210 * @type boolean 211 */ 212 submitAsJSON: null, 213 214 /** 215 * List of validations to execute when the form is submitted. 216 * 217 * @property validations 218 * @type object[] 219 */ 220 validations: null, 221 222 /** 223 * The tooltips used to display an error when errorContainer is set to "tooltip" 224 * 225 * @property tooltips 226 * @type object 227 */ 228 tooltips: null, 229 230 /** 231 * The fields and events that already have a listener attached to them. 232 */ 233 _fieldEvents: {}, 234 235 _FIELD_EVENT_UNDEFINED: undefined, 236 _FIELD_EVENT_LISTEN: 1, 237 _FIELD_EVENT_VALIDATE: 2, 238 239 /** 240 * Name of the attribute to be applied to HTML elements where a HTML validation message must be stored 241 * temporarily 242 */ 243 _VALIDATION_MSG_ATTR: "alf-validation-msg", 244 245 /** 246 * The fields that are considered to have been visited by the user. 247 * Meaning that they will display balloon and red color if users tabs out of them. 248 */ 249 _visitedFields: null, 250 251 /** 252 * Indicates if the field is valid, will be updated by _runValidations 253 */ 254 _valid: null, 255 256 /** 257 * Sets up the required event handlers and prepares the form for use. 258 * NOTE: This must be called after all other setup methods. 259 * 260 * @method init 261 */ 262 init: function() 263 { 264 var form = Dom.get(this.formId); 265 if (form !== null) 266 { 267 if (form.getAttribute("forms-runtime") != "listening") 268 { 269 // add the event to the form and make the scope of the handler this form. 270 Event.addListener(form, "submit", this._submitInvoked, this, true); 271 form.setAttribute("forms-runtime", "listening"); 272 if (this.ajaxSubmit) 273 { 274 form.setAttribute("onsubmit", "return false;"); 275 } 276 } 277 278 // determine if the AJAX and JSON submission should be enabled 279 if (form.getAttribute("enctype") && form.getAttribute("enctype") == "application/json") 280 { 281 this.ajaxSubmit = true; 282 this.submitAsJSON = true; 283 } 284 285 // find the default submit elements if there are no submitIds set 286 if (this.submitElements && this.submitElements.length == 0) 287 { 288 // use a selector to find any submit elements for the form 289 var nodes = Selector.query('#' + this.formId + ' > input[type="submit"]'); 290 for (var x = 0, xx = nodes.length; x < xx; x++) 291 { 292 var elem = nodes[x]; 293 this.submitElements.push(elem.id); 294 } 295 } 296 297 // make sure the submit elements start in the correct state 298 this._runValidations(null, null, Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD); 299 300 // Set up an escape listener so we can close 3rd party widgets such as ballons when escape is clicked 301 var escapeListener = new KeyListener(document, 302 { 303 keys: KeyListener.KEY.ESCAPE 304 }, 305 { 306 fn: function(id, keyEvent) 307 { 308 for (var id in this.tooltips) 309 { 310 if (this.tooltips.hasOwnProperty(id)) 311 { 312 this.tooltips[id].hide(); 313 } 314 } 315 }, 316 scope: this, 317 correctScope: true 318 }); 319 escapeListener.enable(); 320 } 321 else 322 { 323 this._showInternalError("form with id of '" + this.formId + 324 "' could not be located, ensure the form is created after the form element is available."); 325 } 326 }, 327 328 /** 329 * If the form has been tested a boolean is returned to indicate if the form is valid. 330 * If it hasn't been tested null is returned, 331 * 332 * @return {null|Boolean} 333 */ 334 isValid: function() 335 {
336 return this._valid; 337 }, 338 339 /** 340 * Deprecated! 341 * 342 * All forms are always validated before submit 343 * 344 * Enables or disables validation when the form is submitted. 345 * 346 * @method setValidateOnSubmit 347 * @param validate {boolean} true to validate on submission, false 348 * to avoid validation 349 */ 350 setValidateOnSubmit: function(validate) 351 { 352 }, 353 354 /** 355 * Deprecated! 356 * 357 * All fields are now always validated. 358 * 359 * Sets whether all fields are validated when the form is submitted. 360 * 361 * @method setValidateAllOnSubmit 362 * @param validate {boolean} true to validate all fields on submission, false 363 * to stop after the first validation failure 364 */ 365 setValidateAllOnSubmit: function(validateAll) 366 { 367 }, 368 369 /** 370 * Sets the list of ids and/or elements being used to submit the form. 371 * By default the forms runtime will look for and use the first 372 * input field of type submit found in the form being managed. 373 * 374 * @method setSubmitElements 375 * @param submitElements {object | object[]} Single object or array of objects 376 */ 377 setSubmitElements: function(submitElements) 378 { 379 if (!YAHOO.lang.isArray(submitElements)) 380 { 381 this.submitElements[0] = submitElements; 382 } 383 else 384 { 385 this.submitElements = submitElements; 386 } 387 }, 388 389 /** 390 * Sets the container where errors will be displayed. 391 * 392 * @method setErrorContainer 393 * @param container {string} String representing where errors should 394 * be displayed. If the value is not "alert" it's presumed the 395 * string is the id of an HTML object to be used as the error 396 * container 397 */ 398 setErrorContainer: function(container) 399 { 400 this.errorContainer = container; 401 }, 402 403 /** 404 * Dictates if the containers will display one or many errors at a time. 405 * 406 * @method setShowMultipleErrors 407 * @param showMultipleErrors {boolean} Set to true to display multiple errors 408 */ 409 setShowMultipleErrors: function(showMultipleErrors) 410 { 411 this.showMultipleErrors = showMultipleErrors; 412 }, 413 414 /** 415 * Sets a field as being repeatable, this adds a 'plus' sign after the field 416 * thus allowing multiple values to be entered. 417 * 418 * @method setRepeatable 419 * @param fieldId {string} Id of the field the validation is for 420 * @param containerId {string} Id of the element representing the 421 * field 'prototype' i.e. the item that will get cloned. 422 */ 423 setRepeatable: function(fieldId, containerId) 424 { 425 alert("not implemented yet"); 426 }, 427 428 /** 429 * Sets whether the submit elements dynamically update 430 * their state depending on the current values in the form. 431 * The visibility of errors can be controlled via the 432 * showErrors parameter. 433 * 434 * @method setShowSubmitStateDynamically 435 * @param showState {boolean} true to have the elements update dynamically 436 */ 437 setShowSubmitStateDynamically: function(showState) 438 { 439 this.showSubmitStateDynamically = showState; 440 }, 441 442 /** 443 * The forms submit elements are automatically disabled during form submission (and enabled if the form submission fails). 444 * Sets this to true if submit elements shall be enabled after a successful form submission as well. 445 * Thus making the form "reusable". 446 * 447 * @param reusable {boolean} 448 */ 449 setAsReusable: function(reusable) 450 { 451 this.reusable = reusable; 452 }, 453 454 /** 455 * Enables or disables whether the form submits via an AJAX call. 456 * 457 * @method enableAJAXSubmit 458 * @param ajaxSubmit {boolean} true to submit using AJAX, false to submit 459 * using the browser's default behaviour 460 * @param callbacks {object} Optional object representing callback handlers 461 * or messages to use, for example 462 * { 463 * successCallback: yourHandlerObject, 464 * failureCallback: yourHandlerObject,
465 * successMessage: yourMessage, 466 * failureMessage: yourMessage 467 * } 468 * Callback handler objects are of the form: 469 * { 470 * fn: function, // The handler to call when the event fires. 471 * obj: object, // An object to pass back to the handler. 472 * scope: object // The object to use for the scope of the handler. 473 * } 474 */ 475 setAJAXSubmit: function(ajaxSubmit, callbacks) 476 { 477 this.ajaxSubmit = ajaxSubmit; 478 this.ajaxSubmitHandlers = callbacks; 479 }, 480 481 /** 482 * Enables or disables submitting the form data in JSON format. 483 * Setting the enctype attribute of the form to "application/json" 484 * in Firefox will achieve the same result. 485 * 486 * @method setSubmitAsJSON 487 * @param submitAsJSON {boolean} true to submit the form data as JSON, 488 * false to submit one of the standard types "multipart/form-data" 489 * or "application/x-www-form-urlencoded" depending on the enctype 490 * attribute on the form 491 */ 492 setSubmitAsJSON: function(submitAsJSON) 493 { 494 this.submitAsJSON = submitAsJSON; 495 }, 496 497 /** 498 * Set the http method to use for the AJAX call. 499 * 500 * @method setAjaxSubmitMethod 501 * @param ajaxSubmitMethod {string} the http method to use for the AJAX call 502 */ 503 setAjaxSubmitMethod: function(ajaxSubmitMethod) 504 { 505 this.ajaxSubmitMethod = ajaxSubmitMethod; 506 }, 507 508 /** 509 * Decides if the browser shall try and reload the current page if a form submission fails due to auth failure. 510 * 511 * Possible values: 512 * true - browser will NOT reload current page 513 * false - browser will reload current page 514 * null - Will use the default value of noReloadOnAuthFailure in Alfresco.util.Ajax.request 515 * 516 * @method setAjaxNoReloadOnAuthFailure 517 */ 518 setAjaxNoReloadOnAuthFailure: function(noReloadOnAuthFailure) 519 { 520 this.ajaxNoReloadOnAuthFailure = noReloadOnAuthFailure; 521 }, 522 523 /** 524 * Adds validation for a specific field on the form. 525 * Use the when parameter to define when validation shall be triggered. 526 * ALL added validators will be called in the order they were added every time validation is triggered. 527 * Validation can also be manually triggered by calling validate(). 528 * 529 * @method addValidation 530 * @param fieldId {string} Id of the field the validation is for 531 * @param validationHandler {function} Function to call to handle the 532 * actual validation 533 * @param validationArgs {object} Optional object representing the 534 * arguments to pass to the validation handler function 535 * @param when {string} Name of the event when validation shall be triggered, i.e. "keyup", "blur" 536 * If null, the validation will 537 * @param message {string|object|function|null} Message to be displayed to the user when validation fails, 538 * if a function it will be invoked and shall return a string, which may contain HTML, 539 * if an object different values may be provided for rendering a HTML or text message as necessary 540 * in the 'html' and 'text' property values, which may themselves be strings, functions or null, 541 * if omitted or null the default message in the handler is used 542 * @param config {object|function} Contains advanced instructions for the form, i.e. tooltip behaviour when widgets are used 543 * @param config.validationType {string} Set to "mandatory" if a custom mandatory validator is used (rather than Alfresco.forms.mandatory) 544 * @param config.errorField {string|HTMLElement} The element that reflects the error (if not provided fieldId will be used) 545 */ 546 addValidation: function(fieldId, validationHandler, validationArgs, when, message, config) 547 { 548 var field = Dom.get(fieldId); 549 if (field == null) 550 { 551 if (Alfresco.logger.isDebugEnabled()) 552 Alfresco.logger.debug("Ignoring validation for field with id of '" + fieldId + "' as it could not be located."); 553 554 return; 555 } 556 else 557 { 558 // Make sure every validated element has an id set. 559 if (!field.id) 560 { 561 Alfresco.util.generateDomId(field, "form-field-") 562 } 563 } 564 565 if (validationHandler === undefined || validationHandler === null) 566 { 567 if (Alfresco.logger.isDebugEnabled()) 568 Alfresco.logger.debug("Ignoring validation for field with id of '" + fieldId + "' as a validationHandler was not provided."); 569 570 return; 571 } 572 573 if (message === undefined) 574 { 575 message = null; 576 } 577 578 // create object representation of validation
579 var validation = 580 { 581 fieldId: field.id, 582 args: validationArgs, 583 handler: validationHandler, 584 message: message, 585 originalTitle: field.getAttribute("title") || "", 586 event: when, 587 config: config 588 }; 589 590 // add to list of validations 591 this.validations.push(validation); 592 593 if (Alfresco.logger.isDebugEnabled()) 594 Alfresco.logger.debug("Added submit validation for field: " + fieldId + 595 ", using handler: " + 596 (validationHandler.name || YAHOO.lang.dump(validationHandler)) + 597 ", args: " + YAHOO.lang.dump(validationArgs)); 598 599 // if an event has been specified attach an event handler 600 if (when && when.length > 0) 601 { 602 // Add blur listener so we can keep track of visited fields and know when to hide error containers 603 if (this._fieldEvents[field.id + ":" + "blur"] == this._FIELD_EVENT_UNDEFINED) 604 { 605 Event.addListener(field, "blur", this._validationEventFired, field.id, this); 606 this._fieldEvents[field.id + ":" + "blur"] = this._FIELD_EVENT_LISTEN; 607 } 608 609 if (this._fieldEvents[field.id + ":" + when] == this._FIELD_EVENT_UNDEFINED) 610 { 611 // Add a listener to the field event (unless one already had been added for that event) 612 613 // YAHOO doesn't seem to process the propertychange via the addListener so we need to take 614 // matters into our own hands. Listening for the "propertychange" event is required so that 615 // the forms runtime can validate when autocomplete is used in IE. 616 if (YAHOO.env.ua.ie && YAHOO.env.ua.ie < 11 && when == "propertychange") 617 { 618 var _this = this, _fieldId = field.id; 619 field.attachEvent("onpropertychange", function(e) { 620 _this._validationEventFired(e, _fieldId); 621 }); 622 } 623 else 624 { 625 Event.addListener(field, when, this._validationEventFired, field.id, this); 626 } 627 } 628 if (this._fieldEvents[field.id + ":" + when] != this._FIELD_EVENT_VALIDATE) 629 { 630 // Now we will validate on the event 631 this._fieldEvents[field.id + ":" + when] = this._FIELD_EVENT_VALIDATE; 632 } 633 634 // Add focus listener so we can keep track of visited fields andknow when to show error containers 635 if (this._fieldEvents[field.id + ":" + "focus"] == this._FIELD_EVENT_UNDEFINED) 636 { 637 Event.addListener(field, "focus", this._validationEventFired, field.id, this); 638 this._fieldEvents[field.id + ":" + "focus"] = this._FIELD_EVENT_LISTEN; 639 } 640 641 if (Alfresco.logger.isDebugEnabled()) 642 Alfresco.logger.debug("Added field validation for field: " + fieldId + 643 ", using handler: " + 644 (validationHandler.name || YAHOO.lang.dump(validationHandler)) + 645 ", args: " + YAHOO.lang.dump(validationArgs) + 646 ", on event: " + when); 647 } 648 }, 649 650 /** 651 * NOTE! Deprecated. The form runtime now handles error displays by itself. 652 * Kept to make sure custom validation handlers calling this method won't break. 653 * 654 * Adds an error to the form. 655 * 656 * @method addError 657 * @param msg {string} The error message to display 658 * @param field {object} The element representing the field the error occurred on 659 */ 660 addError: function(msg, field) 661 { 662 663 }, 664 665 /** 666 * Adds the given submitElement to the list of submit elements 667 * for the form. 668 * 669 * @method addSubmitElement 670 * @param submitElement Object or string representing the submit element 671 */ 672 addSubmitElement: function(submitElement) 673 { 674 if (submitElement !== null) 675 { 676 // add the new element to the list 677 this.submitElements.push(submitElement); 678 679 if (this.showSubmitStateDynamically) 680 { 681 // force a refresh of the submit state 682 this.validate(); 683 } 684 } 685 }, 686 687 /** 688 * Retrieves the label text for a field 689 * 690 * @method getFieldLabel 691 * @param fieldId {string} The id of the field to get the label for 692 * @return {string} The label for the field or the fieldId if a label could not be found 693 */ 694 getFieldLabel: function(fieldId) 695 { 696 var label = null; 697 698 // lookup the label using the "for" attribute (use the first if multiple found) 699 var nodes = Selector.query('label'); 700 // NOTE: there seems to be a bug in getting label using 'for' or 'htmlFor' 701 // for now get all labels and find the one we want 702 if (nodes.length > 0) 703 { 704 for (var x = 0, xx = nodes.length; x < xx; x++) 705 { 706 var elem = nodes[x]; 707 if ((elem["htmlFor"] == fieldId) || (elem["htmlFor"] == fieldId+"-cntrl")) 708 { 709 // get the text for the label 710 label = elem.firstChild.nodeValue; 711 } 712 } 713 } 714 715 // default to the field id if the label element was not found 716 if (label == null) 717 { 718 label = fieldId; 719 } 720 721 return label; 722 }, 723 724 /** 725 * Retrieves fields by type 726 * 727 * @method getFieldsByType 728 * @param type {string} The type 729 * @return {string} fields by type 730 */ 731 getFieldsByType: function(type) 732 { 733 var nodes = Selector.query(type); 734 return nodes; 735 }, 736 737 /** 738 * Retrieves the data currently held by the form. 739 * 740 * @method getFormData 741 * @return An object representing the form data 742 */ 743 getFormData: function() 744 { 745 // get the form element 746 var form = Dom.get(this.formId); 747 748 // build object representation of the form data 749 return this._buildAjaxForSubmit(form); 750 }, 751 752 /** 753 * Applies a Key Listener to input fields to ensure tabbing only targets elements 754 * that specifically set a "tabindex" attribute. 755 * This has only been seen as an issue with the Firefox web browser, so shouldn't be applied otherwise. 756 * 757 * @method applyTabFix 758 */ 759 applyTabFix: function() 760 { 761 if (YAHOO.env.ua.gecko > 0) 762 { 763 /**
764 * Ensure the Tab key only focusses relevant fields 765 */ 766 var form = Dom.get(this.formId); 767 768 var fnTabFix = function(id, keyEvent) 769 { 770 var event = keyEvent[1]; 771 var target = event.target; 772 if (!target.hasAttribute("tabindex")) 773 { 774 Event.stopEvent(event); 775 var el = Selector.query("[tabindex]", form)[0]; 776 if (Alfresco.util.isVisible(el)) 777 { 778 el.focus(); 779 } 780 } 781 }; 782 783 var tabListener = new KeyListener(form, 784 { 785 keys: KeyListener.KEY.TAB 786 }, 787 fnTabFix, "keyup"); 788 tabListener.enable(); 789 } 790 }, 791 792 /** 793 * Updates the state of all submit elements. 794 * 795 * @method updateSubmitElements 796 */ 797 updateSubmitElements: function() 798 { 799 // To support old forms updating the 800 return this.validate(Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD); 801 }, 802 803 /** 804 * Validates all the fields in the form. 805 * Updates the state of all submit elements if the "showSubmitStateDynamically" option was set to true. 806 * 807 * @method validateField 808 * @param notificationLevel {Object|null} (Optional) The Event that triggered the validation, shall have a type attribute 809 */ 810 validate: function(notificationLevel) 811 { 812 notificationLevel = notificationLevel || Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD; 813 return this._runValidations({}, false, notificationLevel); 814 }, 815 816 /** 817 * Validates all the fields in the form but indicates it was triggered from a specific event and field. 818 * Updates the state of all submit elements if the "showSubmitStateDynamically" option was set to true. 819 * 820 * @method validateField 821 * @param event {Object|null} (Optional) The Event that triggered the validation, shall have a type attribute 822 * @param fieldId {String|null} (Optional) The id 823 */ 824 validateField: function(event, fieldId) 825 { 826 this._validationEventFired(event, fieldId); 827 }, 828 829 /** 830 * Toggles the state of all submit elements. 831 * 832 * @method _toggleSubmitElements 833 * @parameter enabled {boolean} true if the elements shall be enabled 834 */ 835 _toggleSubmitElements: function(enabled) 836 { 837 // make sure all submit elements show correct state 838 for (var x = 0, xx = this.submitElements.length; x < xx; x++) 839 { 840 var currentItem = this.submitElements[x]; 841 if (currentItem) 842 { 843 if (typeof currentItem == "string") 844 { 845 // get the element with the id and set the disabled attribute 846 Dom.get(currentItem).disabled = !enabled; 847 } 848 else 849 { 850 // TODO: for now if an object is passed presume it's a YUI button 851 currentItem.set("disabled", !enabled); 852 } 853 } 854 } 855 }, 856 857 /** 858 * Event handler called when a validation event is fired by any registered field. 859 * 860 * @method _validationEventFired 861 * @param event {object} The event 862 * @param fieldId {String} 863 * @private 864 */ 865 _validationEventFired: function(event, fieldId) 866 { 867 if (Alfresco.logger.isDebugEnabled()) 868 Alfresco.logger.debug("Event has been fired for field: " + fieldId); 869 870 if (event) 871 { 872 if (event.type == "blur") 873 { 874 // Mark field as visited when we leave it 875 if (!this._isFieldVisited(fieldId)) 876 { 877 this._setFieldAsVisited(fieldId); 878 this._runValidations(event, fieldId, Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER); 879 } 880 this._setFieldAsVisited(fieldId); 881 if (this.tooltips[fieldId]) 882 { 883 this.hideErrorContainer(); 884 } 885 } 886 else if (event.type == "focus") 887 { 888 if (!this.tooltips[fieldId]) 889 { 890 this.tooltips[fieldId] = Alfresco.util.createBalloon(this.getFieldValidationEl(fieldId), { 891 effectType: null, 892 effectDuration: 0 893 }); 894 } 895 896 if (YAHOO.util.Dom.hasClass(fieldId, "invalid")) 897 { 898 if (this._fieldEvents[fieldId + ":" + "focus"] != this._FIELD_EVENT_VALIDATE) 899 { 900 // Display error if "focus" event hadn't been added to trigger validation 901 var message = Dom.get(fieldId).getAttribute(this._VALIDATION_MSG_ATTR); 902 this.tooltips[fieldId].html(message); 903 this.tooltips[fieldId].show(); 904 } 905 } 906 } 907 else if (event.type == "propertychange" && !Alfresco.util.arrayContains(["value", "checked"], event.propertyName)) 908 { 909 // "propertychange" events are fired for any attribute change, i.e. "className" & "title", 910 // lets make sure we only validate when necessary 911 return; 912 } 913 } 914 915 916 // Ignore tab, shift, enter and escape clicks 917 if (!event || (event.keyCode != 9 && event.keyCode != 16 && event.keyCode != 13 && event.keyCode != 27)) 918 { 919 if (event && this._fieldEvents[fieldId + ":" + event.type] == this._FIELD_EVENT_VALIDATE) 920 { 921 // Make sure to run the validations anyhow so the tooltips and css error classes are updated & displayed 922 this._runValidations(event, fieldId, Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER); 923 } 924 } 925 }, 926 927 /** 928 * Helper method that inspects the url and adds or refreshes the CSRF token parameter 929 * 930 * @param url 931 * @return {*} 932 * @private 933 */ 934 _setCSRFParameter: function(url) 935 { 936 // Make sure there is a CSRF parameter with the token present in submission 937 var pathAndParams = url.split("?"), 938 tokenParam = Alfresco.util.CSRFPolicy.getParameter() + "=" + encodeURIComponent(Alfresco.util.CSRFPolicy.getToken()); 939 if (pathAndParams.length == 1) 940 { 941 url += "?" + tokenParam; 942 } 943 else 944 { 945 var params = pathAndParams[1].split("&"), 946 pi = 0, 947 nameAndValue, 948 newParams = "", 949 firstParam = true; 950 for (; pi < params.length; pi++) 951 { 952 nameAndValue = params[pi].split("="); 953 if (nameAndValue.length > 0 && nameAndValue[0] == Alfresco.util.CSRFPolicy.getParameter()) 954 { 955 // Don't use the old token param, add a new one after the loop instead 956 } 957 else 958 { 959 // Pass on parameter 960 newParams += firstParam ? "?" : "&"; 961 newParams += params[pi]; 962 firstParam = false;
963 } 964 } 965 if (pi == params.length) 966 { 967 newParams += firstParam ? "?" : "&"; 968 newParams += tokenParam; 969 } 970 url = pathAndParams[0] + newParams; 971 } 972 return url; 973 }, 974 975 /** 976 * Event handler called when the form is submitted. 977 * 978 * @method _submitInvoked 979 * @param event {object} The event 980 * @private 981 */ 982 _submitInvoked: function(event) 983 { 984 if (Alfresco.logger.isDebugEnabled()) 985 Alfresco.logger.debug("Submit invoked on formId: ", this.formId); 986 987 this._setAllFieldsAsVisited(); 988 989 // Run all validators 990 if (this._runValidations(event, null, Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER)) 991 { 992 // validation was successful 993 994 // get the form element 995 var form = Dom.get(this.formId); 996 997 // call the pre-submit function, passing the form for last-chance processing 998 this.doBeforeFormSubmit.fn.call(this.doBeforeFormSubmit.scope, form, this.doBeforeFormSubmit.obj); 999 1000 // fire event to inform any listening components that the form will be submitted 1001 YAHOO.Bubbling.fire("formBeforeSubmit", this); 1002 1003 // should submission be done using AJAX, or let 1004 // the browser do the submit? 1005 if (this.ajaxSubmit) 1006 { 1007 // stop the browser from submitting the form 1008 if (typeof event.cancelBubble !== 'unknown' && typeof event.returnValue !== 'unknown') 1009 { 1010 Event.stopEvent(event); 1011 } 1012 1013 // get the form's action URL 1014 var submitUrl = form.attributes.action.nodeValue; 1015 1016 if (Alfresco.logger.isDebugEnabled()) 1017 { 1018 Alfresco.logger.debug("Performing AJAX submission to url: ", submitUrl); 1019 } 1020 1021 // determine how to submit the form, if the enctype 1022 // on the form is set to "application/json" then 1023 // package the form data as an AJAX string and post 1024 if (form.enctype && form.enctype == "multipart/form-data") 1025 { 1026 var d = form.ownerDocument; 1027 var iframe = d.createElement("iframe"); 1028 iframe.style.display = "none"; 1029 Dom.generateId(iframe, "formAjaxSubmit"); 1030 iframe.name = iframe.id; 1031 document.body.appendChild(iframe); 1032 1033 // makes it possible to target the frame properly in IE. 1034 window.frames[iframe.name].name = iframe.name; 1035 1036 // Pass the CSRF token if the CSRF token filter is enabled 1037 if (Alfresco.util.CSRFPolicy.isFilterEnabled()) 1038 { 1039 form.attributes.action.nodeValue = this._setCSRFParameter(submitUrl); 1040 } 1041 1042 form.target = iframe.name; 1043 form.submit(); 1044 return; 1045 } 1046 else 1047 { 1048 // Only disable submit elements for XMLHttpRequests since we then have a chance of enabling them on failure 1049 this._toggleSubmitElements(false); 1050 } 1051 1052 // create config object to pass to request helper 1053 var config = 1054 { 1055 method: this.ajaxSubmitMethod, 1056 url: submitUrl 1057 }; 1058 1059 if (this.ajaxSubmitHandlers) 1060 { 1061 this.ajaxSubmitHandlers = this.ajaxSubmitHandlers || {}; 1062 config.successMessage = this.ajaxSubmitHandlers.successMessage; 1063 config.successCallback = { 1064 fn: function(response, successCallback) 1065 { 1066 if (Dom.get(this.formId)) 1067 { 1068 // The form still exists 1069 this._resetAllVisitedFields(); 1070 if (this.reusable) 1071 { 1072 if (this.showSubmitStateDynamically) 1073 { 1074 // Update using validation 1075 this.updateSubmitElements(); 1076 } 1077 else 1078 { 1079 // Enable submit buttons 1080 this._toggleSubmitElements(true); 1081 } 1082 } 1083 } 1084 if (successCallback.fn) 1085 { 1086 successCallback.fn.call(successCallback.scope || this, response, successCallback.obj); 1087 } 1088 }, 1089 obj: this.ajaxSubmitHandlers.successCallback || {}, 1090 scope: this 1091 }; 1092 config.failureMessage = this.ajaxSubmitHandlers.failureMessage; 1093 config.failureCallback = { 1094 fn: function(response, failureCallback) 1095 { 1096 if (Dom.get(this.formId)) 1097 { 1098 // The form still exists 1099 this._resetAllVisitedFields(); 1100 if (this.showSubmitStateDynamically) 1101 { 1102 // Update using validation 1103 this.updateSubmitElements(); 1104 } 1105 else 1106 { 1107 // Enable submit buttons 1108 this._toggleSubmitElements(true); 1109 } 1110 } 1111 if (failureCallback.fn) 1112 { 1113 failureCallback.fn.call(failureCallback.scope || this, response, failureCallback.obj); 1114 } 1115 }, 1116 obj: this.ajaxSubmitHandlers.failureCallback || {}, 1117 scope: this 1118 }; 1119 } 1120 if (this.submitAsJSON) 1121 { 1122 var jsonData = this._buildAjaxForSubmit(form); 1123 1124 // set up specific config 1125 config.dataObj = jsonData; 1126 config.noReloadOnAuthFailure = this.ajaxNoReloadOnAuthFailure; 1127 1128 // call the pre-request function, passing the config object for last-chance processing 1129 if (this.doBeforeAjaxRequest.fn.call(this.doBeforeAjaxRequest.scope, config, this.doBeforeAjaxRequest.obj)) 1130 { 1131 if (Alfresco.logger.isDebugEnabled()) 1132 Alfresco.logger.debug("Submitting JSON data: ", config.dataObj); 1133 1134 Alfresco.util.Ajax.jsonRequest(config); 1135 } 1136 else 1137 { 1138 if (Alfresco.logger.isDebugEnabled()) 1139 Alfresco.logger.debug("JSON data request cancelled in doBeforeAjaxRequest()"); 1140 } 1141 this._toggleSubmitElements(true); 1142 } 1143 else 1144 { 1145 if (Alfresco.logger.isDebugEnabled()) 1146 Alfresco.logger.debug("Submitting data in form: ", form.enctype); 1147 1148 // set up specific config 1149 config.dataForm = form; 1150 Alfresco.util.Ajax.request(config); 1151 } 1152 } 1153 else 1154 { 1155 if (form.enctype && form.enctype == "multipart/form-data" && Alfresco.util.CSRFPolicy.isFilterEnabled()) 1156 { 1157 // We are submitting the form as multipart/form-data and leaving the page, make sure the CSRF token is set 1158 form.attributes.action.nodeValue = this._setCSRFParameter(form.attributes.action.nodeValue); 1159 } 1160 } 1161 } 1162 else 1163 { 1164 // stop the event from continuing and sending the form. 1165 Event.stopEvent(event); 1166 1167 if (Alfresco.logger.isDebugEnabled()) 1168 Alfresco.logger.debug("Submission prevented as validation failed"); 1169 1170 // Enable submit buttons 1171 this._toggleSubmitElements(true); 1172 } 1173 }, 1174 1175 /** 1176 * Builds a JSON representation of the current form 1177 * 1178 * @method _buildAjaxForSubmit 1179 * @param form {object} The form object to build the JSON for 1180 * @private 1181 */ 1182 _buildAjaxForSubmit: function(form) 1183 { 1184 if (form !== null) 1185 { 1186 var formData = {}, 1187 length = form.elements.length; 1188 1189 for (var i = 0; i < length; i++) 1190 { 1191 var element = form.elements[i], 1192 name = element.name; 1193 1194 if (name == "-" || element.disabled || element.type === "button") 1195 { 1196 continue; 1197 } 1198 if (name == undefined || name == "") 1199 {
1200 name = element.id; 1201 } 1202 var value = element.value; 1203 if (name) 1204 { 1205 // check whether the input element is an array value 1206 if ((name.length > 2) && (name.substring(name.length - 2) == '[]')) 1207 { 1208 name = name.substring(0, name.length - 2); 1209 if (formData[name] === undefined) 1210 { 1211 formData[name] = new Array(); 1212 } 1213 formData[name].push(value); 1214 } 1215 // check whether the input element is an object literal value 1216 else if (name.indexOf(".") > 0) 1217 { 1218 var names = name.split("."); 1219 var obj = formData; 1220 var index; 1221 for (var j = 0, k = names.length - 1; j < k; j++) 1222 { 1223 index = names[j]; 1224 if (obj[index] === undefined) 1225 { 1226 obj[index] = {}; 1227 } 1228 obj = obj[index]; 1229 } 1230 obj[names[j]] = value; 1231 } 1232 else if (!((element.type === "checkbox" || element.type === "radio") && !element.checked)) 1233 { 1234 if (element.type == "select-multiple") 1235 { 1236 for (var j = 0, jj = element.options.length; j < jj; j++) 1237 { 1238 if (element.options[j].selected) 1239 { 1240 if (formData[name] == undefined) 1241 { 1242 formData[name] = new Array(); 1243 } 1244 formData[name].push(element.options[j].value); 1245 } 1246 } 1247 } 1248 else 1249 { 1250 formData[name] = value; 1251 } 1252 } 1253 } 1254 } 1255 1256 return formData; 1257 } 1258 }, 1259 1260 /** 1261 * Checks if a field has been visited 1262 * 1263 * @function _isFieldVisited 1264 * @param fieldId THe fieldId to mark as edited 1265 * @return {boolean} true of the field has been edited (or the user has tried to submit the form) 1266 */ 1267 _isFieldVisited: function(fieldId) 1268 { 1269 return (YAHOO.lang.isBoolean(this._visitedFields) && this._visitedFields) || 1270 (YAHOO.lang.isObject(this._visitedFields) && this._visitedFields[fieldId]); 1271 }, 1272 1273 /** 1274 * Marks a field as visited 1275 * 1276 * @function _setFieldAsVisited 1277 * @param fieldId {string} 1278 */ 1279 _setFieldAsVisited: function(fieldId) 1280 { 1281 if (!YAHOO.lang.isBoolean(this._visitedFields) && YAHOO.lang.isObject(this._visitedFields)) 1282 { 1283 return this._visitedFields[fieldId] = true; 1284 } 1285 }, 1286 1287 /** 1288 * Marks all fields as visited 1289 * 1290 * @function _setAllFieldsEdited 1291 */ 1292 _setAllFieldsAsVisited: function() 1293 { 1294 this._visitedFields = true; 1295 }, 1296 1297 _resetAllVisitedFields: function() 1298 { 1299 this._visitedFields = {}; 1300 }, 1301 1302 1303 _getConfig: function(config, configName, defaultValue) 1304 { 1305 var c = config || {}; 1306 if (YAHOO.lang.isFunction(config)) 1307 { 1308 c = config(); 1309 } 1310 var result = Alfresco.util.findValueByDotNotation(c, configName); 1311 return (result != undefined || result != null) ? result : defaultValue; 1312 }, 1313 1314 _isMandatoryValidator: function(val) 1315 { 1316 return val.handler == Alfresco.forms.validation.mandatory || (this._getConfig(val.config, "validationType", "invalid") == "mandatory"); 1317 }, 1318 1319 /** 1320 * Executes all registered validations and returns result. 1321 * 1322 * @method _runValidations 1323 * @parameter event {Object|null} The event that triggered the validation OR null if validation was programmatically called 1324 * @parameter fieldId {string|null|boolean} The current el that triggered the event OR null if validation was programmatically called 1325 * @private 1326 */ 1327 _runValidations: function(event, fieldId, notificationLevel) 1328 { 1329 var allErrors = [], 1330 errorsByField = {}, 1331 errorsByFieldText = {}, 1332 allWarnings = [], 1333 warningsByField = {}, 1334 fieldMsg, 1335 message, 1336 textMessage, 1337 validationType, 1338 MANDATORY = "mandatory",
1339 INVALID = "invalid", 1340 field, 1341 valFieldId, 1342 val, 1343 suppressValidationNotification, 1344 primaryErrorFieldId = null; 1345 1346 // Iterate through all validations (for all enabled fields) so we can tell if the complete form is valid or not 1347 for (var x = 0, xx = this.validations.length; x < xx; x++) 1348 { 1349 val = this.validations[x]; 1350 1351 field = Dom.get(val.fieldId); 1352 if (field !== null && !field.disabled) 1353 { 1354 textMessage = null; 1355 valFieldId = field.getAttribute("id"); 1356 errorsByField[valFieldId] = errorsByField[valFieldId] || []; 1357 errorsByFieldText[valFieldId] = errorsByFieldText[valFieldId] || []; 1358 warningsByField[valFieldId] = warningsByField[valFieldId] || []; 1359 1360 // Make sure invalid fields are showed as mandatory until the user has had a chance of changing the value 1361 validationType = this._isMandatoryValidator(val) && !this._isFieldVisited(valFieldId) ? MANDATORY : INVALID; 1362 if (typeof val.message === "object" && val.message != null) 1363 { 1364 message = val.message.html || null; 1365 textMessage = val.message.text || null; 1366 } 1367 else 1368 { 1369 message = val.message || null; 1370 } 1371 if (message) 1372 { 1373 if (YAHOO.lang.isFunction(message)) 1374 { 1375 // Validator wanted to create error message manually 1376 message = message.call(this, val.args); 1377 } 1378 else 1379 { 1380 // Make sure message parameters based on validator args are resolved 1381 message = YAHOO.lang.substitute(message, val.args); 1382 } 1383 } 1384 else 1385 { 1386 // Message is missing, use these as a last resort 1387 var key; 1388 if (this._isMandatoryValidator(val)) 1389 { 1390 key = "Alfresco.forms.validation.mandatory.message"; 1391 } 1392 else 1393 { 1394 key = "Alfresco.forms.validation.invalid.message"; 1395 } 1396 message = Alfresco.util.message(key); 1397 } 1398 if (textMessage) 1399 { 1400 if (YAHOO.lang.isFunction(textMessage)) 1401 { 1402 // Validator wanted to create error message manually 1403 textMessage = textMessage.call(this, val.args); 1404 } 1405 else 1406 { 1407 // Make sure message parameters based on validator args are resolved 1408 textMessage = YAHOO.lang.substitute(textMessage, val.args); 1409 } 1410 } 1411 else 1412 { 1413 // Last resort - strip HTML tags from the HTML message 1414 textMessage = message.replace(/<\/?[^>]+(>|$)/g, ""); 1415 } 1416 1417 // Make sure that validation notifications aren't triggered by events from other validations for the same field 1418 suppressValidationNotification = (validationType == INVALID) && 1419 (event != null && event.type != "blur" && event.type != val.event && event.keyCode != 13) && 1420 (fieldId == valFieldId); 1421 1422 if (!val.handler(field, val.args, null, this, true, message)) 1423 { 1424 // The field is invalid 1425 1426 // Lets see if the validator wants to use another Dom id as context for the error container. 1427 var errorField = Dom.get(this._getConfig(val.config, "errorField", field)); 1428 if (!errorField.id) 1429 { 1430 // All fields must have a dom id 1431 Alfresco.util.generateDomId(errorField); 1432 } 1433 if (errorField.id != fieldId && validationType == INVALID) 1434 { 1435 // Make sure that error containers are created for custom fields as well 1436 errorsByField[errorField.id] = errorsByField[errorField.id] || []; 1437 errorsByFieldText[errorField.id] = errorsByFieldText[errorField.id] || []; 1438 if (errorsByField[errorField.id].indexOf(message) == -1) 1439 { 1440 errorsByField[errorField.id].push(message); 1441 } 1442 if (errorsByFieldText[errorField.id].indexOf(textMessage) == -1) 1443 { 1444 errorsByFieldText[errorField.id].push(textMessage); 1445 } 1446 } 1447 1448 // Mark the first field with an error as the primary field (will be used if user tried to submit form) 1449 if (primaryErrorFieldId == null) 1450 { 1451 primaryErrorFieldId = errorField.id; 1452 } 1453 1454 if (suppressValidationNotification) 1455 { 1456 // There was a validation error for this field but it was configured to get displayed on another event 1457 continue; 1458 } 1459 1460 // Prepare error message including field name (the label in the dom) 1461 fieldMsg = YAHOO.lang.trim(this.getFieldLabel(valFieldId)) || ""; 1462 if (fieldMsg.length > 0) 1463 { 1464 if (fieldMsg.indexOf(":") < 0) 1465 { 1466 fieldMsg += ":"; 1467 } 1468 fieldMsg += " ";
1469 } 1470 fieldMsg += message; 1471 1472 // Update error indication css classes 1473 if (validationType == INVALID) 1474 { 1475 1476 allErrors.push({ id: valFieldId, msg: fieldMsg }); 1477 // we don't want to add the same text 1478 if (errorsByField[valFieldId].indexOf(message) == -1) 1479 { 1480 errorsByField[valFieldId].push(message); 1481 } 1482 // we don't want to add the same text 1483 if (errorsByFieldText[valFieldId].indexOf(textMessage) == -1) 1484 { 1485 errorsByFieldText[valFieldId].push(textMessage); 1486 } 1487 1488 // Remove the mandatory class since it now is invalid 1489 if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD) 1490 { 1491 YAHOO.util.Dom.removeClass(field, MANDATORY); 1492 if (field == errorField) 1493 { 1494 YAHOO.util.Dom.addClass(field, INVALID); 1495 } 1496 else 1497 { 1498 YAHOO.util.Dom.removeClass(field, INVALID); 1499 } 1500 1501 // Update message with the first validation failure (ALF-19012) 1502 if (errorsByField[valFieldId].length == 0) 1503 { 1504 field.setAttribute("title", textMessage); 1505 field.setAttribute(this._VALIDATION_MSG_ATTR, message); 1506 } 1507 else 1508 { 1509 field.setAttribute("title", errorsByFieldText[valFieldId][0]); 1510 var validationMsgAttr = ''; 1511 for (var mess = 0; mess < errorsByField[valFieldId].length; mess++) 1512 { 1513 if (mess > 0 && !this.showMultipleErrors) 1514 { 1515 break; 1516 } 1517 validationMsgAttr += '<div>' + errorsByField[valFieldId][mess] + '</div>'; 1518 } 1519 field.setAttribute(this._VALIDATION_MSG_ATTR, validationMsgAttr); 1520 } 1521 } 1522 1523 } 1524 else 1525 { 1526 // Actual errors have higher priority than a "mandatory error" 1527 if (errorsByField[valFieldId].length == 0) 1528 { 1529 if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD) 1530 { 1531 YAHOO.util.Dom.removeClass(field, INVALID); 1532 if (field == errorField) 1533 { 1534 YAHOO.util.Dom.addClass(field, MANDATORY); 1535 } 1536 else 1537 { 1538 YAHOO.util.Dom.removeClass(field, INVALID); 1539 } 1540 field.setAttribute("title", message); 1541 } 1542 field.setAttribute(this._VALIDATION_MSG_ATTR, message); 1543 } 1544 warningsByField[valFieldId].push(message); 1545 allWarnings.push({ id: valFieldId, msg: fieldMsg }); 1546 } 1547 1548 YAHOO.Bubbling.fire("formValidationError", { 1549 msg: fieldMsg, 1550 field: field, 1551 type: validationType 1552 }); 1553 } 1554 else 1555 { 1556 if (suppressValidationNotification) 1557 { 1558 // There was a validation error, but it was configured to be displayed on another event 1559 continue; 1560 } 1561 1562 if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD) 1563 { 1564 1565 if (errorsByField[valFieldId].length == 0) 1566 { 1567 YAHOO.util.Dom.removeClass(field, INVALID); 1568 } 1569 if (warningsByField[valFieldId].length == 0) 1570 { 1571 YAHOO.util.Dom.removeClass(field, MANDATORY); 1572 } 1573 if (errorsByField[valFieldId].length == 0 && warningsByField[valFieldId].length == 0) 1574 { 1575 if (field.getAttribute("title") != val.originalTitle) 1576 { 1577 field.setAttribute("title", val.originalTitle); 1578 } 1579 field.setAttribute(this._VALIDATION_MSG_ATTR, ""); 1580 if (this.tooltips[valFieldId]) 1581 { 1582 this.tooltips[valFieldId].html(""); 1583 this.tooltips[valFieldId].hide(); 1584 } 1585 } 1586 } 1587 } 1588 } 1589 } 1590 1591 // Use focused field as context for the error container ... 1592 var errorFieldId = (document.activeElement && document.activeElement.id ? document.activeElement.id : null); 1593 if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER) 1594 { 1595 if ((event == null || event.type == "submit") && primaryErrorFieldId && 1596 (!warningsByField[errorFieldId] || warningsByField[errorFieldId].length == 0) && 1597 (!errorsByField[errorFieldId] || errorsByField[errorFieldId].length == 0)) 1598 { 1599 // ... unless the user tried to submit the form, then use the forst field with an error 1600 errorFieldId = primaryErrorFieldId; 1601 var el = this.getFieldValidationEl(Dom.get(errorFieldId)); 1602 if (Alfresco.util.isVisible(el)) 1603 { 1604 if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 9) 1605 { 1606 // No action - this causes a script error on IE8 and below. 1607 } 1608 else if (YAHOO.lang.isFunction(el.focus)) 1609 { 1610 el.focus(); 1611 } 1612 } 1613 } 1614 1615 if (this.errorContainer !== null && errorFieldId && errorsByField[errorFieldId]) 1616 { 1617 if (this.errorContainer === "tooltip") 1618 { 1619 /* 1620 for (var key in this.tooltips) 1621 { 1622 if (this.tooltips.hasOwnProperty(key) && key != errorFieldId) 1623 { 1624 this.tooltips[key].hide(); 1625 } 1626 } 1627 */ 1628 if (errorsByField[errorFieldId].length > 0) 1629 { 1630 if (!this.tooltips[errorFieldId]) 1631 { 1632 this.tooltips[errorFieldId] = Alfresco.util.createBalloon(this.getFieldValidationEl(errorFieldId), { 1633 effectType: null, 1634 effectDuration: 0 1635 }); 1636 } 1637 1638 var html = ''; 1639 for (var i = 0; i < errorsByField[errorFieldId].length; i++) 1640 { 1641 if (i > 0 && !this.showMultipleErrors) 1642 { 1643 break; 1644 } 1645 html += '<div>' + errorsByField[errorFieldId][i] + '</div>'; 1646 } 1647 this.tooltips[errorFieldId].html(html); 1648 this.tooltips[errorFieldId].show(); 1649 } 1650 else if (this.tooltips[errorFieldId]) 1651 { 1652 this.tooltips[errorFieldId].html(""); 1653 this.tooltips[errorFieldId].hide(); 1654 } 1655 } 1656 else if (this.errorContainer === "alert" && allErrors.length > 0) 1657 { 1658 var msg = ''; 1659 for (var i = 0; i < allErrors.length; i++) 1660 { 1661 if (i > 0 && !this.showMultipleErrors) 1662 { 1663 break; 1664 } 1665 msg += allErrors[i] + '\n'; 1666 } 1667 alert(msg); 1668 } 1669 else if (YAHOO.lang.isString(this.errorContainer)) 1670 { 1671 var htmlNode = Dom.get(this.errorContainer); 1672 if (htmlNode !== null) 1673 { 1674 var html = ''; 1675 for (var i = 0; i < allErrors.length; i++) 1676 { 1677 if (i > 0 && !this.showMultipleErrors) 1678 { 1679 break; 1680 } 1681 html += '<div><label for="' + allErrors[i].id + '">' + allErrors[i].msg + '</label></div>'; 1682 } 1683 htmlNode.style.display = "block"; 1684 htmlNode.innerHTML = html; 1685 } 1686 } 1687 } 1688 } 1689
1690 this._valid = primaryErrorFieldId == null; 1691 1692 // update submit elements state, if required 1693 if (this.showSubmitStateDynamically) 1694 { 1695 this._toggleSubmitElements(this._valid); 1696 } 1697 1698 return this._valid; 1699 }, 1700 1701 getFieldValidationEl: function(fieldId) 1702 { 1703 var el = Dom.get(fieldId); 1704 if ((el.tagName.toLowerCase() == "input" && el.type == "hidden") || !Alfresco.util.isVisible(el)) 1705 { 1706 return el.parentNode; 1707 } 1708 return el; 1709 }, 1710 1711 hideErrorContainer: function() 1712 { 1713 if (this.errorContainer === "tooltip") 1714 { 1715 for (var key in this.tooltips) 1716 { 1717 if (this.tooltips.hasOwnProperty(key)) 1718 { 1719 this.tooltips[key].hide(); 1720 } 1721 } 1722 } 1723 else if (this.errorContainer === "alert") 1724 { 1725 // Not applicable 1726 } 1727 else if (YAHOO.lang.isString(this.errorContainer)) 1728 { 1729 // todo Filter out errors for the field 1730 } 1731 }, 1732 1733 /** 1734 * Displays an internal form error message. 1735 * 1736 * @method _showInternalError 1737 * @param msg {string} The error message to display 1738 * @param field {object} The element representing the field the error occurred on 1739 * @private 1740 */ 1741 _showInternalError: function(msg, field) 1742 { 1743 this.addError("Internal Form Error: " + msg, field); 1744 }, 1745 1746 reset: function() 1747 { 1748 this._resetAllVisitedFields(); 1749 Dom.get(this.formId).reset(); 1750 this.validate(); 1751 } 1752 }; 1753})(); 1754 1755(function() 1756{ 1757 1758 /** 1759 * Mandatory validation handler, tests that the given field has a value. 1760 * 1761 * @method mandatory 1762 * @param field {object} The element representing the field the validation is for 1763 * @param args {object} Not used 1764 * @param event {object} The event that caused this handler to be called, maybe null 1765 * @param form {object} The forms runtime class instance the field is being managed by 1766 * @static 1767 */ 1768 Alfresco.forms.validation.mandatory = function mandatory(field, args, event, form) 1769 { 1770 if (Alfresco.logger.isDebugEnabled()) 1771 Alfresco.logger.debug("Validating mandatory state of field '" + field.id + "'"); 1772 1773 var valid = true; 1774 1775 if (field.type && field.type == "radio") 1776 { 1777 // wouldn't a radio button normally have a default 1778 // 'checked' option? 1779 1780 var formElem = Dom.get(form.formId), 1781 radios = formElem[field.name], 1782 anyChecked = false; 1783 for (var x = 0, xx = radios.length; x < xx; x++) 1784 { 1785 if (radios[x].checked) 1786 { 1787 anyChecked = true; 1788 break; 1789 } 1790 1791 } 1792 1793 valid = anyChecked; 1794 } 1795 else if (field.type && field.type == "checkbox") 1796 { 1797 valid = field.checked; 1798 } 1799 else 1800 { 1801 valid = YAHOO.lang.trim(field.value).length !== 0; 1802 } 1803 1804 return valid; 1805 }; 1806 1807 1808 /** 1809 * Password match validation handler, tests that the given field's value matches another password field. 1810 * 1811 * @method passwordMatch 1812 * @param field {object} The element representing the field the validation is for 1813 * @param args {object} 1814 * @param args.el {HTMLElement|String} The input element that contains the element to coimpare against. 1815 * @param event {object} The event that caused this handler to be called, maybe null 1816 * @param form {object} The forms runtime class instance the field is being managed by 1817 * @static 1818 */ 1819 Alfresco.forms.validation.passwordMatch = function passwordMatch(field, args, event, form) 1820 { 1821 if (Alfresco.logger.isDebugEnabled()) 1822 Alfresco.logger.debug("Validating password match of field '" + field.id + "' using args: " + YAHOO.lang.dump(args)); 1823 if (YAHOO.lang.trim(field.value).length == 0) 1824 { 1825 return true; 1826 } 1827 1828 var valid = false; 1829 var myArgs = YAHOO.lang.merge( 1830 { 1831 el: null 1832 }, args); 1833 1834 if (myArgs.el) 1835 { 1836 var el = YAHOO.util.Dom.get(myArgs.el); 1837 if (el.value == field.value) 1838 { 1839 valid = true; 1840 } 1841 } 1842 1843 return valid; 1844 }; 1845 1846 /** 1847 * Validate that the content of a password adheres to the policy provided in the supplied configuration 1848 * 1849 * @method passwordContent 1850 * @param field {object} The element representing the field the validation is for 1851 * @param args {object} Object providing the password content policy 1852 * { 1853 * minUpper: 1, // Minimum number of uppercase characters 1854 * minLower: 1, // Minimum number of lowercase characters 1855 * minNumeric: 1, // Minimum number of numeric characters 1856 * minSymbols: 1 // Minimum number of special characters (!,@,#,$,%,^,&,*,?,_,~) 1857 * } 1858 * @param event {object} The event that caused this handler to be called, maybe null 1859 * @param form {object} The forms runtime class instance the field is being managed by 1860 * @static 1861 * @returns {Boolean} True if the password adheres to policy, false otherwise 1862 */ 1863 Alfresco.forms.validation.passwordContent = function passwordContent(field, args, event, form) 1864 { 1865 if (Alfresco.logger.isDebugEnabled()) 1866 Alfresco.logger.debug("Validating password content of field '" + field.id + 1867 "' using args: " + YAHOO.lang.dump(args));
1868 // Empty input elements should not be marked as invalid, leave this to the mandatory check 1869 if (YAHOO.lang.trim(field.value).length == 0) 1870 { 1871 return true; 1872 } 1873 var myArgs = YAHOO.lang.merge( 1874 { 1875 minUpper: 0, 1876 minLower: 0, 1877 minNumeric: 0, 1878 minSymbols: 0 1879 }, args), 1880 password = field.value, 1881 DIGITS = /\d/g, 1882 SPECIAL_CHARS = /([!,@,#,$,%,^,&,*,?,_,~])/g, 1883 numeric = (password.match(DIGITS) || []).length, 1884 symbols = (password.match(SPECIAL_CHARS) || []).length, 1885 upper = 0, lower = 0, ch; 1886 for (var i = 0; i < password.length; i++) 1887 { 1888 ch = password.charAt(i); 1889 if (ch.toUpperCase() != ch.toLowerCase()) 1890 { 1891 // Ok now we now it is an actual character (can't use regexp since they dont handle foreign characters) 1892 if (ch.toUpperCase() == ch) 1893 { 1894 upper++; 1895 } 1896 if (ch.toLowerCase() == ch) 1897 { 1898 lower++; 1899 } 1900 } 1901 } 1902 return myArgs.minUpper <= upper && myArgs.minLower <= lower && myArgs.minNumeric <= numeric && myArgs.minSymbols <= symbols; 1903 }; 1904 1905 /** 1906 * Length validation handler, tests that the given field's value has either 1907 * a minimum and/or maximum length. 1908 * 1909 * @method length 1910 * @param field {object} The element representing the field the validation is for 1911 * @param args {object} Object representing the minimum and maximum length, and whether to crop content 1912 * { 1913 * min: 3, 1914 * max: 10, 1915 * crop: true 1916 * } 1917 * @param event {object} The event that caused this handler to be called, maybe null 1918 * @param form {object} The forms runtime class instance the field is being managed by 1919 * @static 1920 */ 1921 Alfresco.forms.validation.length = function length(field, args, event, form) 1922 { 1923 if (Alfresco.logger.isDebugEnabled()) 1924 Alfresco.logger.debug("Validating length of field '" + field.id + 1925 "' using args: " + YAHOO.lang.dump(args)); 1926 var valid = true; 1927 var myArgs = YAHOO.lang.merge( 1928 { 1929 min: -1, 1930 max: -1, 1931 crop: false, 1932 includeWhitespace: true, 1933 ignoreEmpty: false 1934 }, args); 1935 1936 if (YAHOO.lang.trim(field.value).length == 0 && myArgs.ignoreEmpty) 1937 { 1938 return true; 1939 } 1940 1941 if (myArgs.minLength) 1942 { 1943 myArgs.min = myArgs.minLength; 1944 } 1945 1946 if (myArgs.maxLength) 1947 { 1948 myArgs.max = myArgs.maxLength; 1949 } 1950 1951 var length = myArgs.includeWhitespace ? field.value.length : YAHOO.lang.trim(field.value).length; 1952 1953 if (myArgs.min != -1 && length < myArgs.min) 1954 { 1955 valid = false; 1956 } 1957 1958 if (myArgs.max != -1 && length > myArgs.max) 1959 { 1960 valid = false; 1961 if (myArgs.crop) 1962 { 1963 if (myArgs.includeWhitespace) 1964 { 1965 field.value = YAHOO.lang.trim(field.value); 1966 } 1967 if (field.value.length > myArgs.max) 1968 { 1969 field.value = field.value.substring(0, myArgs.max); 1970 } 1971 if (field.type && field.type == "textarea") 1972 { 1973 field.scrollTop = field.scrollHeight; 1974 } 1975 valid = true; 1976 } 1977 } 1978 1979 return valid; 1980 }; 1981 1982 /** 1983 * Number validation handler, tests that the given field's value is a number. 1984 * 1985 * @method number 1986 * @param field {object} The element representing the field the validation is for 1987 * @param args {object} Optional object containing a "repeating" flag 1988 * { 1989 * repeating: true 1990 * } 1991 * @param event {object} The event that caused this handler to be called, maybe null 1992 * @param form {object} The forms runtime class instance the field is being managed by 1993 * @static 1994 */ 1995 Alfresco.forms.validation.number = function number(field, args, event, form) 1996 { 1997 if (Alfresco.logger.isDebugEnabled()) 1998 Alfresco.logger.debug("Validating field '" + field.id + "' is a number"); 1999 2000 var repeating = false;
2001 2002 // determine if field has repeating values 2003 if (args !== null && args.repeating) 2004 { 2005 repeating = true; 2006 } 2007 2008 var valid = true; 2009 if (repeating) 2010 { 2011 // as it's repeating there could be multiple comma separated values 2012 var values = field.value.split(","); 2013 for (var i = 0; i < values.length; i++) 2014 { 2015 valid = (isNaN(values[i]) == false); 2016 2017 if (!valid) 2018 { 2019 // stop as soon as we find an invalid value 2020 break; 2021 } 2022 } 2023 } 2024 else 2025 { 2026 valid = (isNaN(field.value) == false); 2027 } 2028 2029 return valid; 2030 }; 2031 2032 /** 2033 * Number range validation handler, tests that the given field's value has either 2034 * a minimum and/or maximum value. 2035 * 2036 * @method numberRange 2037 * @param field {object} The element representing the field the validation is for 2038 * @param args {object} Object representing the minimum and maximum value, and optionally 2039 * a "repeating" flag, for example 2040 * { 2041 * min: 18, 2042 * max: 30, 2043 * repeating: true 2044 * } 2045 * @param event {object} The event that caused this handler to be called, maybe null 2046 * @param form {object} The forms runtime class instance the field is being managed by 2047 * @static 2048 */ 2049 Alfresco.forms.validation.numberRange = function numberRange(field, args, event, form) 2050 { 2051 if (Alfresco.logger.isDebugEnabled()) { 2052 Alfresco.logger.debug("Validating number range of field '" + field.id + "' using args: " + YAHOO.lang.dump(args)); 2053 } 2054 2055 var valid = true; 2056 var value = field.value.toString(); 2057 2058 if (value.length > 0) 2059 { 2060 if (!Alfresco.forms.validation.number(field, args, null, null, true, null)) 2061 { 2062 valid = false; 2063 } 2064 else 2065 { 2066 // ACE-3690: NaN instead of -1 to indicate a non-present value 2067 var min = NaN; 2068 var max = NaN; 2069 var repeating = false; 2070 2071 if (args.min !== undefined) 2072 { 2073 min = parseInt(args.min); 2074 } 2075 2076 if (args.minValue !== undefined) 2077 { 2078 min = parseInt(args.minValue); 2079 } 2080 2081 if (args.max !== undefined) 2082 { 2083 max = parseInt(args.max); 2084 } 2085 2086 if (args.maxValue !== undefined) 2087 { 2088 max = parseInt(args.maxValue); 2089 } 2090 2091 // determine if field has repeating values 2092 if (args !== null && args.repeating) 2093 { 2094 repeating = true; 2095 } 2096 2097 var valid = true; 2098 if (repeating) 2099 { 2100 // as it's repeating there could be multiple comma separated values 2101 var values = value.split(","); 2102 for (var i = 0; i < values.length; i++) 2103 { 2104 if (min != -1 && values[i] < min) 2105 { 2106 valid = false; 2107 } 2108 2109 if (max != -1 && values[i] > max) 2110 { 2111 valid = false; 2112 } 2113 2114 if (!valid) 2115 { 2116 // stop as soon as we find an invalid value 2117 break; 2118 } 2119 } 2120 } 2121 else 2122 { 2123 if (!isNaN(min) && value < min) 2124 { 2125 valid = false; 2126 } 2127 2128 if (!isNaN(max) && value > max) 2129 { 2130 valid = false; 2131 } 2132 } 2133 } 2134 } 2135 2136 return valid; 2137 }; 2138 2139 /** 2140 * Node name validation handler, tests that the given field's value is a valid 2141 * name for a node in the repository. 2142 * 2143 * @method nodeName 2144 * @param field {object} The element representing the field the validation is for 2145 * @param args {object} Not used 2146 * @param event {object} The event that caused this handler to be called, maybe null 2147 * @param form {object} The forms runtime class instance the field is being managed by 2148 * @static 2149 */ 2150 Alfresco.forms.validation.nodeName = function nodeName(field, args, event, form) 2151 { 2152 if (Alfresco.logger.isDebugEnabled()) 2153 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid node name"); 2154 2155 return Alfresco.forms.validation.name(field, args, event, form); 2156 }; 2157 2158 /** 2159 * File name validation handler, tests that the given field's value is a valid 2160 * name for a node in the repository. 2161 * 2162 * @method fileName 2163 * @param field {object} The element representing the field the validation is for 2164 * @param args {object} Not used 2165 * @param event {object} The event that caused this handler to be called, maybe null 2166 * @param form {object} The forms runtime class instance the field is being managed by 2167 * @param silent {boolean} Determines whether the user should be informed upon failure 2168 * @param message {string} Message to display when validation fails, maybe null 2169 * @static 2170 */ 2171 Alfresco.forms.validation.fileName = function fileName(field, args, event, form) 2172 { 2173 if (Alfresco.logger.isDebugEnabled()) 2174 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid file name"); 2175 2176 return Alfresco.forms.validation.name(field, args, event, form); 2177 }; 2178 2179 2180 /** 2181 * Name validation handler, tests that the given field's value is a valid 2182 * name for a node name or file name in the repository. 2183 * 2184 * @method nodeName 2185 * @param field {object} The element representing the field the validation is for 2186 * @param args {object} Not used 2187 * @param event {object} The event that caused this handler to be called, maybe null 2188 * @param form {object} The forms runtime class instance the field is being managed by 2189 * @static 2190 */ 2191 Alfresco.forms.validation.name = function name(field, args, event, form) 2192 { 2193 if (!args) 2194 { 2195 args = {}; 2196 } 2197 2198 /**
2199 * Pattern for disallowing leading and trailing spaces. See CHK-6614 2200 * args.pattern = /([\"\*\\\>\<\?\/\:\|]+)|([\.]?[\.]+$)|(^[ \t]+|[ \t]+$)/; 2201 */ 2202 2203 args.pattern = /([\"\*\\\>\<\?\/\:\|]+)|([\.]?[\.]+$)|(^[ \t]+|[ \t]+$)/; 2204 args.match = false; 2205 2206 return Alfresco.forms.validation.regexMatch(field, args, event, form); 2207 }; 2208 2209 /** 2210 * Wiki page title validation handler, tests that the given field's value is a valid 2211 * name for a node in the repository. 2212 * 2213 * @method nodeName 2214 * @param field {object} The element representing the field the validation is for 2215 * @param args {object} Not used 2216 * @param event {object} The event that caused this handler to be called, maybe null 2217 * @param form {object} The forms runtime class instance the field is being managed by 2218 * @param silent {boolean} Determines whether the user should be informed upon failure 2219 * @param message {string} Message to display when validation fails, maybe null 2220 * @static 2221 */ 2222 Alfresco.forms.validation.wikiTitle = function wikiTitle(field, args, event, form, silent, message) 2223 { 2224 if (Alfresco.logger.isDebugEnabled()) 2225 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid node name"); 2226 2227 if (!args) 2228 { 2229 args = {}; 2230 } 2231 2232 args.pattern = /([#\\\?\/\|]+)|([\.]?[\.]+$)/; 2233 args.match = false; 2234 2235 return Alfresco.forms.validation.regexMatch(field, args, event, form, silent, message); 2236 }; 2237 2238 /** 2239 * NodeRef validation handler, tests that the given field's value is a valid 2240 * nodeRef identifier for a node in the repository. 2241 * 2242 * @method nodeRef 2243 * @param field {object} The element representing the field the validation is for 2244 * @param args {object} Not used 2245 * @param event {object} The event that caused this handler to be called, maybe null 2246 * @param form {object} The forms runtime class instance the field is being managed by 2247 * @static 2248 */ 2249 Alfresco.forms.validation.nodeRef = function nodeRef(field, args, event, form) 2250 { 2251 if (Alfresco.logger.isDebugEnabled()) 2252 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid noderef"); 2253 2254 if (!args) 2255 { 2256 args = {}; 2257 } 2258 2259 args.pattern = /^[^\:^ ]+\:\/\/[^\:^ ]+\/[^ ]+$/; 2260 2261 return Alfresco.forms.validation.regexMatch(field, args, event, form); 2262 }; 2263 2264 2265 /** 2266 * Email validation handler, tests that the given field's value is a valid 2267 * email address. 2268 * 2269 * @method email 2270 * @param field {object} The element representing the field the validation is for 2271 * @param args {object} Not used 2272 * @param event {object} The event that caused this handler to be called, maybe null 2273 * @param form {object} The forms runtime class instance the field is being managed by 2274 * @static 2275 */ 2276 Alfresco.forms.validation.email = function email(field, args, event, form) 2277 { 2278 if (Alfresco.logger.isDebugEnabled()) 2279 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid email address"); 2280 2281 if (!args) 2282 { 2283 args = {}; 2284 } 2285 2286 var valid = true; 2287 if (field.value && field.value.length > 0) 2288 { 2289 //Strip out the name and surrounding angle brackets, if present. 2290 var start = field.value.indexOf("<"); 2291 if (start >= 0) 2292 { 2293 start = start + 1; 2294 var end = field.value.lastIndexOf(">"); 2295 if (end > start) 2296 { 2297 field.value = field.value.substr(start, (end -start)); 2298 } 2299 } 2300 2301 var emailFirstCharIndex = field.value.indexOf('"'); 2302 2303 /* MNT-7031 fix. Added validation according RFC 2822. 2304 If email local part starts with " (double quote) pattern for special characters space and 2305 "(),:;<>@[\] (ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91â93) with restrictions is used. 2306 Otherwise pattern for uppercase and lowercase English letters, digits, 2307 characters !#$%&'*+-/=?^_`{|}~ ((ASCII: 33, 35â39, 42, 43, 45, 47, 61, 63, 94â96, 123â126)) , dot is used 2308 */ 2309 if (emailFirstCharIndex == 0) 2310 { 2311 args.pattern = /^("[-A-Za-z0-9\xc0-\xff\(\)<>\[\]\\:,;@\".\" *"!#$%&'*+\/=?^_`{}~|]*")+@([\.A-Za-z0-9_-])*[A-Za-z0-9_-]$/; 2312 } 2313 else 2314 { 2315 args.pattern = /^([-A-Za-z0-9\xc0-\xff!#$%&'*+\/=?^_`{}~|]+\.)*[-A-Za-z0-9\xc0-\xff!#$%&'*+\/=?^_`{}|~_]+@([\.A-Za-z0-9_-])*[A-Za-z0-9_-]$/; 2316 } 2317 2318 args.match = true; 2319 2320 valid = Alfresco.forms.validation.regexMatch(field, args, event, form); 2321 } 2322 return valid; 2323 }; 2324 2325 /** 2326 * Phone validation handler 2327 * 2328 * @method phone 2329 * @param field {object} The element representing the field the validation is for 2330 * @param args {object} Not used 2331 * @param event {object} The event that caused this handler to be called, maybe null 2332 * @param form {object} The forms runtime class instance the field is being managed by 2333 * @param silent {boolean} Determines whether the user should be informed upon failure 2334 * @param message {string} Message to display when validation fails, maybe null 2335 * @static 2336 */ 2337 Alfresco.forms.validation.phone = function phone(field, args, event, form, silent, message) 2338 { 2339 if (Alfresco.logger.isDebugEnabled()) 2340 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid phone number"); 2341 2342 if (!args) 2343 { 2344 args = {}; 2345 } 2346 2347 args.pattern = /^[0-9\(\)\[\]\-\+\*#\\:\/,; ]+$/; 2348 args.match = true; 2349 2350 return Alfresco.forms.validation.regexMatch(field, args, event, form, silent, message); 2351 }; 2352 2353 2354 /**
2355 * Time validation handler, tests that the given field's value is a valid time value. 2356 * 2357 * @method time 2358 * @param field {object} The element representing the field the validation is for 2359 * @param args {object} Not used 2360 * @param event {object} The event that caused this handler to be called, maybe null 2361 * @param form {object} The forms runtime class instance the field is being managed by 2362 * @static 2363 */ 2364 Alfresco.forms.validation.time = function time(field, args, event, form) 2365 { 2366 if (Alfresco.logger.isDebugEnabled()) 2367 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid time value"); 2368 2369 if (!args) 2370 { 2371 args = {}; 2372 } 2373 2374 args.pattern = /^([0-1]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/; 2375 args.match = true; 2376 2377 return Alfresco.forms.validation.regexMatch(field, args, event, form); 2378 }; 2379 2380 /** 2381 * URL validation handler, tests that the given field's value is a valid URL 2382 * 2383 * @method url 2384 * @param field {object} The element representing the field the validation is for 2385 * @param args {object} Not used 2386 * @param event {object} The event that caused this handler to be called, maybe null 2387 * @param form {object} The forms runtime class instance the field is being managed by 2388 * @static 2389 */ 2390 Alfresco.forms.validation.url = function url(field, args, event, form) 2391 { 2392 if (Alfresco.logger.isDebugEnabled()) 2393 Alfresco.logger.debug("Validating field '" + field.id + "' is a valid URL"); 2394 2395 var expression = /(ftp|http|https):\/\/[\w\-_]+(\.[\w\-_]+)*([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/, 2396 valid = true; 2397 2398 if (field.value.length > 0) 2399 { 2400 // Check an empty string replacement returns an empty string 2401 var pattern = new RegExp(expression); 2402 valid = field.value.replace(pattern, "") === ""; 2403 } 2404 2405 return valid; 2406 }; 2407 2408 2409 /** 2410 * Regular expression validation handler, tests that the given field's value matches 2411 * the supplied regular expression. 2412 * 2413 * @method regexMatch 2414 * @param field {object} The element representing the field the validation is for 2415 * @param args {object} Object representing the expression. 2416 * The args object should have the form of: 2417 * { 2418 * pattern: {regexp}, // A regular expression 2419 * match: {boolean} // set to false if the regexp should NOT match the input, default is true 2420 * } 2421 * An example to validate a field represents an email address can look like: 2422 * { 2423 * pattern: /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/ 2424 * } 2425 * @param event {object} The event that caused this handler to be called, maybe null 2426 * @param form {object} The forms runtime class instance the field is being managed by 2427 * @static 2428 */ 2429 Alfresco.forms.validation.regexMatch = function regexMatch(field, args, event, form) 2430 { 2431 if (Alfresco.logger.isDebugEnabled()) 2432 Alfresco.logger.debug("Validating regular expression of field '" + field.id + 2433 "' using args: " + YAHOO.lang.dump(args)); 2434 var valid = true; 2435 2436 if (field.value && field.value.length > 0) 2437 { 2438 // The pattern SHOULD match by default 2439 if (args.match === undefined) 2440 { 2441 args.match = true; 2442 } 2443 2444 // Check if the patterns match 2445 var pattern = new RegExp(args.pattern); 2446 valid = pattern.test(field.value); 2447 2448 // Adjust the result if the test wasn't intended to match 2449 if (!args.match) 2450 { 2451 valid = !valid; 2452 } 2453 } 2454 2455 return valid; 2456 }; 2457 2458 2459 /** 2460 * Repository regular expression handler, simply used as a pass through to the 2461 * standard regexMatch handler after converting the paramater names. 2462 * 2463 * @method repoRegexMatch 2464 * @param field {object} The element representing the field the validation is for 2465 * @param args {object} Not used 2466 * @param event {object} The event that caused this handler to be called, maybe null 2467 * @param form {object} The forms runtime class instance the field is being managed by 2468 * @static 2469 */ 2470 Alfresco.forms.validation.repoRegexMatch = function repoRegexMatch(field, args, event, form) 2471 { 2472 // convert parameters 2473 args.pattern = args.expression; 2474 args.match = args.requiresMatch; 2475 2476 // call the standard regex handler 2477 return Alfresco.forms.validation.regexMatch(field, args, event, form); 2478 }; 2479 2480 /** 2481 * Validation handler for a valid date and time, currently this simply looks for the 2482 * presence of the 'invalid' class applied to the relevant field. This implies that this 2483 * validation handler must be added after any other handlers that determine validity. 2484 * 2485 * @method validDateTime 2486 * @param field {object} The element representing the field the validation is for 2487 * @param args {object} Not used 2488 * @param event {object} The event that caused this handler to be called, maybe null 2489 * @param form {object} The forms runtime class instance the field is being managed by 2490 * @static 2491 */ 2492 Alfresco.forms.validation.validDateTime = function validDateTime(field, args, event, form) 2493 { 2494 if (Alfresco.logger.isDebugEnabled()) 2495 Alfresco.logger.debug("Validating field '" + field.id + "' has a valid date and time"); 2496 2497 return !YAHOO.util.Dom.hasClass(field, "invalid"); 2498 }; 2499 2500 /** 2501 * Validation handler for the repository 'list of values' constraint. As the UI 2502 * handles this by displaying the list of allowable values this handler is a dummy 2503 * placeholder. 2504 * 2505 * @method listOfValues 2506 * @param field {object} The element representing the field the validation is for 2507 * @param args {object} The list of allowable values 2508 * @param event {object} The event that caused this handler to be called, maybe null 2509 * @param form {object} The forms runtime class instance the field is being managed by 2510 * @static 2511 */ 2512 Alfresco.forms.validation.inList = function inList(field, args, event, form) 2513 { 2514 return true; 2515 }; 2516 2517})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.