PageSourceSearch

https://disclosure.gse.com.gh:8443/share/res/js/forms-runtime_8a365a3f7d03cab92527ab60a179bb91.js

js gse.com.gh collected 2026-10-02 10:06:57 UTC 91,108 bytes, 2,517 lines download raw bytes

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.