1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2003-2007 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.validators
13{
14
15import flash.events.Event;
16import flash.events.EventDispatcher;
17import flash.events.IEventDispatcher;
18import mx.binding.BindingManager;
19import mx.core.IMXMLObject;
20import mx.events.FlexEvent;
21import mx.events.ValidationResultEvent;
22import mx.managers.ISystemManager;
23import mx.managers.SystemManager;
24import mx.resources.IResourceManager;
25import mx.resources.ResourceManager;
26import mx.validators.IValidator;
27
28//--------------------------------------
29//  Events
30//--------------------------------------
31
32/**
33 *  Dispatched when validation succeeds.
34 *
35 *  @eventType mx.events.ValidationResultEvent.VALID
36 *
37 *  @langversion 3.0
38 *  @playerversion Flash 9
39 *  @playerversion AIR 1.1
40 *  @productversion Flex 3
41 */
42[Event(name="valid", type="mx.events.ValidationResultEvent")]
43
44/**
45 *  Dispatched when validation fails.
46 *
47 *  @eventType mx.events.ValidationResultEvent.INVALID
48 *
49 *  @langversion 3.0
50 *  @playerversion Flash 9
51 *  @playerversion AIR 1.1
52 *  @productversion Flex 3
53 */
54[Event(name="invalid", type="mx.events.ValidationResultEvent")]
55
56//--------------------------------------
57//  Other metadata
58//--------------------------------------
59
60[ResourceBundle("core")]
61[ResourceBundle("validators")]
62
63/**
64 *  The Validator class is the base class for all Flex validators.
65 *  This class implements the ability for a validator to make a field
66 *  required, which means that the user must enter a value in the field
67 *  or the validation fails.
68 *
69 *  @mxml
70 *
71 *  <p>The Validator class defines the following tag attributes,
72 *  which all of its subclasses inherit:</p>
73 *
74 *  <pre>
75 *  &lt;mx:Validator
76 *    enabled="true|false"
77 *    listener="<i>Value of the source property</i>"
78 *    property="<i>No default</i>"
79 *    required="true|false"
80 *    requiredFieldError="This field is required."
81 *    source="<i>No default</i>"
82 *    trigger="<i>Value of the source property</i>"
83 *    triggerEvent="valueCommit"
84 *  /&gt;
85 *  </pre>
86 *
87 *  @see mx.events.ValidationResultEvent
88 *  @see mx.validators.ValidationResult
89 *  @see mx.validators.RegExpValidationResult
90 *
91 *  @includeExample examples/SimpleValidatorExample.mxml
92 *
93 *  @langversion 3.0
94 *  @playerversion Flash 9
95 *  @playerversion AIR 1.1
96 *  @productversion Flex 3
97 */
98public class Validator extends EventDispatcher implements IMXMLObject,IValidator
99{
100    include "../core/Version.as";
101
102    //--------------------------------------------------------------------------
103    //
104    //  Class constants
105    //
106    //--------------------------------------------------------------------------
107
108    /**
109     *  A string containing the upper- and lower-case letters
110     *  of the Roman alphabet  ("A" through "Z" and "a" through "z").
111     *
112     *  @langversion 3.0
113     *  @playerversion Flash 9
114     *  @playerversion AIR 1.1
115     *  @productversion Flex 3
116     */
117    protected static const ROMAN_LETTERS:String =
118        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
119
120    /**
121     *  A String containing the decimal digits 0 through 9.
122     *
123     *  @langversion 3.0
124     *  @playerversion Flash 9
125     *  @playerversion AIR 1.1
126     *  @productversion Flex 3
127     */
128    protected static const DECIMAL_DIGITS:String = "0123456789";
129
130    //--------------------------------------------------------------------------
131    //
132    //  Class methods
133    //
134    //--------------------------------------------------------------------------
135
136    /**
137     *  Invokes all the validators in the <code>validators</code> Array.
138     *  Returns an Array containing one ValidationResultEvent object
139     *  for each validator that failed.
140     *  Returns an empty Array if all validators succeed.
141     *
142     *  @param validators An Array containing the Validator objects to execute.
143     *
144     *  @return Array of ValidationResultEvent objects, where the Array
145     *  contains one ValidationResultEvent object for each validator
146     *  that failed.
147     *  The Array is empty if all validators succeed.
148     *
149     *  @langversion 3.0
150     *  @playerversion Flash 9
151     *  @playerversion AIR 1.1
152     *  @productversion Flex 3
153     */
154    public static function validateAll(validators:Array):Array
155    {
156        var result:Array = [];
157
158        var n:int = validators.length;
159        for (var i:int = 0; i < n; i++)
160        {
161            var v:IValidator = validators[i] as IValidator;
162            if (v && v.enabled)
163            {
164	            var resultEvent:ValidationResultEvent = v.validate();
165
166	            if (resultEvent.type != ValidationResultEvent.VALID)
167	                result.push(resultEvent);
168	        }
169        }
170
171        return result;
172    }
173
174    /**
175     *  @private
176     */
177    private static function findObjectFromString(doc:Object,
178                                                 value:String):Object
179    {
180        var obj:Object = doc;
181        var parts:Array = value.split(".");
182
183        var n:int = parts.length;
184        for (var i:int = 0; i < n; i++)
185        {
186            try
187            {
188                obj = obj[parts[i]];
189
190                // There's no guarantee that the objects have
191                // already been created when this function fires;
192                // for example, in the deferred instantiation case,
193                // this function fires before the object for validation
194                // has been created.
195                if (obj == null)
196                {
197                    //return true;
198                }
199            }
200            catch(error:Error)
201            {
202                if ((error is TypeError) &&
203                    (error.message.indexOf("null has no properties") != -1))
204                {
205                    var resourceManager:IResourceManager =
206                        ResourceManager.getInstance();
207                    var message:String = resourceManager.getString(
208                        "validators", "fieldNotFound", [ value ]);
209                    throw new Error(message);
210                }
211                else
212                {
213                    throw error;
214                }
215            }
216        }
217
218        return obj;
219    }
220
221    /**
222     *  @private
223     */
224    private static function trimString(str:String):String
225    {
226        var startIndex:int = 0;
227        while (str.indexOf(' ', startIndex) == startIndex)
228        {
229            ++startIndex;
230        }
231
232        var endIndex:int = str.length - 1;
233        while (str.lastIndexOf(' ', endIndex) == endIndex)
234        {
235            --endIndex;
236        }
237
238        return endIndex >= startIndex ?
239               str.slice(startIndex, endIndex + 1) :
240               "";
241    }
242
243    //--------------------------------------------------------------------------
244    //
245    //  Constructor
246    //
247    //--------------------------------------------------------------------------
248
249    /**
250     *  Constructor.
251     *
252     *  @langversion 3.0
253     *  @playerversion Flash 9
254     *  @playerversion AIR 1.1
255     *  @productversion Flex 3
256     */
257    public function Validator()
258    {
259        super();
260
261        // Register as a weak listener for "change" events from ResourceManager.
262        // If Validators registered as a strong listener,
263        // they wouldn't get garbage collected.
264        resourceManager.addEventListener(
265            Event.CHANGE, resourceManager_changeHandler, false, 0, true);
266
267        resourcesChanged();
268    }
269
270    //--------------------------------------------------------------------------
271    //
272    //  Variables
273    //
274    //--------------------------------------------------------------------------
275
276    /**
277     *  @private
278     */
279    private var document:Object;
280
281    //--------------------------------------------------------------------------
282    //
283    //  Properties
284    //
285    //--------------------------------------------------------------------------
286
287    //----------------------------------
288    //  actualTrigger
289    //----------------------------------
290
291    /**
292     *  Contains the trigger object, if any,
293     *  or the source object. Used to determine the listener object
294     *  for the <code>triggerEvent</code>.
295     *
296     *  @langversion 3.0
297     *  @playerversion Flash 9
298     *  @playerversion AIR 1.1
299     *  @productversion Flex 3
300     */
301    protected function get actualTrigger():IEventDispatcher
302    {
303        if (_trigger)
304            return _trigger;
305
306        else if (_source)
307            return _source as IEventDispatcher;
308
309        return null;
310    }
311
312    //----------------------------------
313    //  actualListeners
314    //----------------------------------
315
316    /**
317     *  Contains an Array of listener objects, if any,
318     *  or the source object. Used to determine which object
319     *  to notify about the validation result.
320     *
321     *  @langversion 3.0
322     *  @playerversion Flash 9
323     *  @playerversion AIR 1.1
324     *  @productversion Flex 3
325     */
326    protected function get actualListeners():Array
327    {
328        var result:Array = [];
329
330        if (_listener)
331            result.push(_listener);
332
333        else if (_source)
334            result.push(_source);
335
336        return result;
337    }
338
339    //----------------------------------
340    //  enabled
341    //----------------------------------
342
343    /**
344     *  @private
345     *  Storage for the enabled property.
346     */
347    private var _enabled:Boolean = true;
348
349    [Inspectable(category="General", defaultValue="true")]
350
351    /**
352     *  Setting this value to <code>false</code> will stop the validator
353     *  from performing validation.
354     *  When a validator is disabled, it dispatch no events,
355     *  and the <code>validate()</code> method returns null.
356     *
357     *  @default true
358     *
359     *  @langversion 3.0
360     *  @playerversion Flash 9
361     *  @playerversion AIR 1.1
362     *  @productversion Flex 3
363     */
364    public function get enabled():Boolean
365    {
366        return _enabled;
367    }
368
369    /**
370     *  @private
371     */
372    public function set enabled(value:Boolean):void
373    {
374        _enabled = value;
375    }
376
377    //----------------------------------
378    //  listener
379    //----------------------------------
380
381    /**
382     *  @private
383     *  Storage for the listener property.
384     */
385    private var _listener:Object;
386
387    [Inspectable(category="General")]
388
389    /**
390     *  Specifies the validation listener.
391     *
392     *  <p>If you do not specify a listener,
393     *  Flex uses the value of the <code>source</code> property.
394     *  After Flex determines the source component,
395     *  it changes the border color of the component,
396     *  displays an error message for a failure,
397     *  or hides any existing error message for a successful validation.</p>
398     *
399     *
400     *  @langversion 3.0
401     *  @playerversion Flash 9
402     *  @playerversion AIR 1.1
403     *  @productversion Flex 3
404     */
405
406    /* This behavior has been removed.
407     *  <p>If Flex does not find an appropriate listener,
408     *  validation errors propagate to the Application object, causing Flex
409     *  to display an Alert box containing the validation error message.</p>
410     *
411     *  <p>Specifying <code>this</code> causes the validation error
412     *  to propagate to the Application object,
413     *  and displays an Alert box containing the validation error message.</p>
414     *
415     *  @langversion 3.0
416     *  @playerversion Flash 9
417     *  @playerversion AIR 1.1
418     *  @productversion Flex 3
419     */
420    public function get listener():Object
421    {
422        return _listener;
423    }
424
425    /**
426     *  @private
427     */
428    public function set listener(value:Object):void
429    {
430        removeListenerHandler();
431        _listener = value;
432        addListenerHandler();
433    }
434
435    //----------------------------------
436    //  property
437    //----------------------------------
438
439    /**
440     *  @private
441     *  Storage for the property property.
442     */
443    private var _property:String;
444
445    [Inspectable(category="General")]
446
447    /**
448     *  A String specifying the name of the property
449     *  of the <code>source</code> object that contains
450     *  the value to validate.
451     *  The property is optional, but if you specify <code>source</code>,
452     *  you should set a value for this property as well.
453     *
454     *  @default null
455     *
456     *  @langversion 3.0
457     *  @playerversion Flash 9
458     *  @playerversion AIR 1.1
459     *  @productversion Flex 3
460     */
461    public function get property():String
462    {
463        return _property;
464    }
465
466    /**
467     *  @private
468     */
469    public function set property(value:String):void
470    {
471        _property = value;
472    }
473
474    //----------------------------------
475    //  required
476    //----------------------------------
477
478    [Inspectable(category="General", defaultValue="true")]
479
480    /**
481     *  If <code>true</code>, specifies that a missing or empty
482     *  value causes a validation error.
483     *
484     *  @default true
485     *
486     *  @langversion 3.0
487     *  @playerversion Flash 9
488     *  @playerversion AIR 1.1
489     *  @productversion Flex 3
490     */
491    public var required:Boolean = true;
492
493    //----------------------------------
494    //  resourceManager
495    //----------------------------------
496
497    /**
498     *  @private
499     *  Storage for the resourceManager property.
500     */
501    private var _resourceManager:IResourceManager = ResourceManager.getInstance();
502
503	/**
504	 *  @private
505	 *  This metadata suppresses a trace() in PropertyWatcher:
506	 *  "warning: unable to bind to property 'resourceManager' ..."
507	 */
508	[Bindable("unused")]
509
510    /**
511     *  @copy mx.core.UIComponent#resourceManager
512     *
513     *  @langversion 3.0
514     *  @playerversion Flash 9
515     *  @playerversion AIR 1.1
516     *  @productversion Flex 3
517     */
518    protected function get resourceManager():IResourceManager
519    {
520        return _resourceManager;
521    }
522
523    //----------------------------------
524    //  source
525    //----------------------------------
526
527    /**
528     *  @private
529     *  Storage for the source property.
530     */
531    private var _source:Object;
532
533    [Inspectable(category="General")]
534
535    /**
536     *  Specifies the object containing the property to validate.
537     *  Set this to an instance of a component or a data model.
538     *  You use data binding syntax in MXML to specify the value.
539     *  This property supports dot-delimited Strings
540     *  for specifying nested properties.
541     *
542     *  If you specify a value to the <code>source</code> property,
543     *  then you should specify a value to the <code>property</code>
544     *  property as well.
545     *  The <code>source</code> property is optional.
546     *
547     *  @default null
548     *
549     *  @langversion 3.0
550     *  @playerversion Flash 9
551     *  @playerversion AIR 1.1
552     *  @productversion Flex 3
553     */
554    public function get source():Object
555    {
556        return _source;
557    }
558
559    /**
560     *  @private
561     */
562    public function set source(value:Object):void
563    {
564        if (_source == value)
565            return;
566
567        if (value is String)
568        {
569            var message:String = resourceManager.getString(
570                "validators", "SAttribute", [ value ]);
571            throw new Error(message);
572        }
573
574        // Remove the listener from the old source.
575        removeTriggerHandler();
576        removeListenerHandler();
577
578        _source = value;
579
580        // Listen for the trigger event on the new source.
581        addTriggerHandler();
582        addListenerHandler();
583    }
584
585    //----------------------------------
586    //  subFields
587    //----------------------------------
588
589    /**
590     *  An Array of Strings containing the names for the properties contained
591     *  in the <code>value</code> Object passed to the <code>validate()</code> method.
592     *  For example, CreditCardValidator sets this property to
593     *  <code>[ "cardNumber", "cardType" ]</code>.
594     *  This value means that the <code>value</code> Object
595     *  passed to the <code>validate()</code> method
596     *  should contain a <code>cardNumber</code> and a <code>cardType</code> property.
597     *
598     *  <p>Subclasses of the Validator class that
599     *  validate multiple data fields (like CreditCardValidator and DateValidator)
600     *  should assign this property in their constructor. </p>
601     *
602     *  @langversion 3.0
603     *  @playerversion Flash 9
604     *  @playerversion AIR 1.1
605     *  @productversion Flex 3
606     */
607    protected var subFields:Array = [];
608
609    //----------------------------------
610    //  trigger
611    //----------------------------------
612
613    /**
614     *  @private
615     *  Storage for the trigger property.
616     */
617    private var _trigger:IEventDispatcher;
618
619    [Inspectable(category="General")]
620
621    /**
622     *  Specifies the component generating the event that triggers the validator.
623     *  If omitted, by default Flex uses the value of the <code>source</code> property.
624     *  When the <code>trigger</code> dispatches a <code>triggerEvent</code>,
625     *  validation executes.
626     *
627     *  @langversion 3.0
628     *  @playerversion Flash 9
629     *  @playerversion AIR 1.1
630     *  @productversion Flex 3
631     */
632    public function get trigger():IEventDispatcher
633    {
634        return _trigger;
635    }
636
637    /**
638     *  @private
639     */
640    public function set trigger(value:IEventDispatcher):void
641    {
642        removeTriggerHandler();
643        _trigger = value;
644        addTriggerHandler();
645    }
646
647    //----------------------------------
648    //  triggerEvent
649    //----------------------------------
650
651    /**
652     *  @private
653     *  Storage for the triggerEvent property.
654     */
655    private var _triggerEvent:String = FlexEvent.VALUE_COMMIT;
656
657    [Inspectable(category="General")]
658
659    /**
660     *  Specifies the event that triggers the validation.
661     *  If omitted, Flex uses the <code>valueCommit</code> event.
662     *  Flex dispatches the <code>valueCommit</code> event
663     *  when a user completes data entry into a control.
664     *  Usually this is when the user removes focus from the component,
665     *  or when a property value is changed programmatically.
666     *  If you want a validator to ignore all events,
667     *  set <code>triggerEvent</code> to the empty string ("").
668     *
669     *  @langversion 3.0
670     *  @playerversion Flash 9
671     *  @playerversion AIR 1.1
672     *  @productversion Flex 3
673     */
674    public function get triggerEvent():String
675    {
676        return _triggerEvent;
677    }
678
679    /**
680     *  @private
681     */
682    public function set triggerEvent(value:String):void
683    {
684        if (_triggerEvent == value)
685            return;
686
687        removeTriggerHandler();
688        _triggerEvent = value;
689        addTriggerHandler();
690    }
691
692    //--------------------------------------------------------------------------
693    //
694    //  Properties: Errors
695    //
696    //--------------------------------------------------------------------------
697
698    //----------------------------------
699    //  requiredFieldError
700    //----------------------------------
701
702    /**
703     *  @private
704     *  Storage for the requiredFieldError property.
705     */
706    private var _requiredFieldError:String;
707
708    /**
709     *  @private
710     */
711    private var requiredFieldErrorOverride:String;
712
713    [Inspectable(category="Errors", defaultValue="null")]
714
715    /**
716     *  Error message when a value is missing and the
717     *  <code>required</code> property is <code>true</code>.
718     *
719     *  @default "This field is required."
720     *
721     *  @langversion 3.0
722     *  @playerversion Flash 9
723     *  @playerversion AIR 1.1
724     *  @productversion Flex 3
725     */
726    public function get requiredFieldError():String
727    {
728        return _requiredFieldError;
729    }
730
731    /**
732     *  @private
733     */
734    public function set requiredFieldError(value:String):void
735    {
736        requiredFieldErrorOverride = value;
737
738        _requiredFieldError = value != null ?
739                              value :
740                              resourceManager.getString(
741                                  "validators", "requiredFieldError");
742    }
743
744    //--------------------------------------------------------------------------
745    //
746    //  Methods: IMXMLObject
747    //
748    //--------------------------------------------------------------------------
749
750     /**
751      *  Called automatically by the MXML compiler when the Validator
752      *  is created using an MXML tag.
753      *
754      *  @param document The MXML document containing this Validator.
755      *
756      *  @param id Ignored.
757      *
758      *  @langversion 3.0
759      *  @playerversion Flash 9
760      *  @playerversion AIR 1.1
761      *  @productversion Flex 3
762      */
763     public function initialized(document:Object, id:String):void
764     {
765        this.document = document;
766     }
767
768    //--------------------------------------------------------------------------
769    //
770    //  Methods
771    //
772    //--------------------------------------------------------------------------
773
774    /**
775     *  This method is called when a Validator is constructed,
776     *  and again whenever the ResourceManager dispatches
777     *  a <code>"change"</code> Event to indicate
778     *  that the localized resources have changed in some way.
779     *
780     *  <p>This event will be dispatched when you set the ResourceManager's
781     *  <code>localeChain</code> property, when a resource module
782     *  has finished loading, and when you call the ResourceManager's
783     *  <code>update()</code> method.</p>
784     *
785     *  <p>Subclasses should override this method and, after calling
786     *  <code>super.resourcesChanged()</code>, do whatever is appropriate
787     *  in response to having new resource values.</p>
788     *
789     *  @langversion 3.0
790     *  @playerversion Flash 9
791     *  @playerversion AIR 1.1
792     *  @productversion Flex 3
793     */
794    protected function resourcesChanged():void
795    {
796        requiredFieldError = requiredFieldErrorOverride;
797    }
798
799    /**
800     *  @private
801     */
802    private function addTriggerHandler():void
803    {
804        if (actualTrigger)
805            actualTrigger.addEventListener(_triggerEvent, triggerHandler);
806    }
807
808    /**
809     *  @private
810     */
811    private function removeTriggerHandler():void
812    {
813        if (actualTrigger)
814            actualTrigger.removeEventListener(_triggerEvent, triggerHandler);
815    }
816
817    /**
818     *  Sets up all of the listeners for the
819     *  <code>valid</code> and <code>invalid</code>
820     *  events dispatched from the validator. Subclasses of the Validator class
821     *  should first call the <code>removeListenerHandler()</code> method,
822     *  and then the <code>addListenerHandler()</code> method if
823     *  the value of one of their listeners or sources changes.
824     *  The CreditCardValidator and DateValidator classes use this function internally.
825     *
826     *  @langversion 3.0
827     *  @playerversion Flash 9
828     *  @playerversion AIR 1.1
829     *  @productversion Flex 3
830     */
831    protected function addListenerHandler():void
832    {
833        var actualListener:Object;
834        var listeners:Array = actualListeners;
835
836        var n:int = listeners.length;
837        for (var i:int = 0; i < n; i++)
838        {
839            actualListener = listeners[i];
840            if (actualListener is IValidatorListener)
841            {
842                addEventListener(ValidationResultEvent.VALID,
843                                 IValidatorListener(actualListener).validationResultHandler);
844
845                addEventListener(ValidationResultEvent.INVALID,
846                                 IValidatorListener(actualListener).validationResultHandler);
847            }
848        }
849    }
850
851    /**
852     *  Disconnects all of the listeners for the
853     *  <code>valid</code> and <code>invalid</code>
854     *  events dispatched from the validator. Subclasses should first call the
855     *  <code>removeListenerHandler()</code> method and then the
856     *  <code>addListenerHandler</code> method if
857     *  the value of one of their listeners or sources changes.
858     *  The CreditCardValidator and DateValidator classes use this function internally.
859     *
860     *  @langversion 3.0
861     *  @playerversion Flash 9
862     *  @playerversion AIR 1.1
863     *  @productversion Flex 3
864     */
865    protected function removeListenerHandler():void
866    {
867        var actualListener:Object;
868        var listeners:Array = actualListeners;
869
870        var n:int = listeners.length;
871        for (var i:int = 0; i < n; i++)
872        {
873            actualListener = listeners[i];
874            if (actualListener is IValidatorListener)
875            {
876                removeEventListener(ValidationResultEvent.VALID,
877                                    IValidatorListener(actualListener).validationResultHandler);
878
879                removeEventListener(ValidationResultEvent.INVALID,
880                                    IValidatorListener(actualListener).validationResultHandler);
881            }
882        }
883    }
884
885    /**
886     *  Returns <code>true</code> if <code>value</code> is not null.
887     *
888     *  @param value The value to test.
889     *
890     *  @return <code>true</code> if <code>value</code> is not null.
891     *
892     *  @langversion 3.0
893     *  @playerversion Flash 9
894     *  @playerversion AIR 1.1
895     *  @productversion Flex 3
896     */
897    protected function isRealValue(value:Object):Boolean
898    {
899        return (value != null);
900    }
901
902    /**
903     *  Performs validation and optionally notifies
904     *  the listeners of the result.
905     *
906     *  @param value Optional value to validate.
907     *  If null, then the validator uses the <code>source</code> and
908     *  <code>property</code> properties to determine the value.
909     *  If you specify this argument, you should also set the
910     *  <code>listener</code> property to specify the target component
911     *  for any validation error messages.
912     *
913     *  @param suppressEvents If <code>false</code>, then after validation,
914     *  the validator will notify the listener of the result.
915     *
916     *  @return A ValidationResultEvent object
917     *  containing the results of the validation.
918     *  For a successful validation, the
919     *  <code>ValidationResultEvent.results</code> Array property is empty.
920     *  For a validation failure, the
921     *  <code>ValidationResultEvent.results</code> Array property contains
922     *  one ValidationResult object for each field checked by the validator,
923     *  both for fields that failed the validation and for fields that passed.
924     *  Examine the <code>ValidationResult.isError</code>
925     *  property to determine if the field passed or failed the validation.
926     *
927     *  @see mx.events.ValidationResultEvent
928     *  @see mx.validators.ValidationResult
929     *
930     *  @langversion 3.0
931     *  @playerversion Flash 9
932     *  @playerversion AIR 1.1
933     *  @productversion Flex 3
934     */
935    public function validate(
936                        value:Object = null,
937                        suppressEvents:Boolean = false):ValidationResultEvent
938    {
939        if (value == null)
940            value = getValueFromSource();
941
942        if (isRealValue(value) || required)
943        {
944            // Validate if the target is required or our value is non-null.
945            return processValidation(value, suppressEvents);
946        }
947        else
948        {
949            // We assume if value is null and required is false that
950            // validation was successful.
951            var resultEvent:ValidationResultEvent =
952                new ValidationResultEvent(ValidationResultEvent.VALID);
953            if (!suppressEvents && _enabled)
954            {
955            	dispatchEvent(resultEvent);
956            }
957            return resultEvent;
958        }
959    }
960
961    /**
962     *  Returns the Object to validate. Subclasses, such as the
963     *  CreditCardValidator and DateValidator classes,
964     *  override this method because they need
965     *  to access the values from multiple subfields.
966     *
967     *  @return The Object to validate.
968     *
969     *  @langversion 3.0
970     *  @playerversion Flash 9
971     *  @playerversion AIR 1.1
972     *  @productversion Flex 3
973     */
974    protected function getValueFromSource():Object
975    {
976        var message:String;
977
978        if (_source && _property)
979        {
980            return _source[_property];
981        }
982
983        else if (!_source && _property)
984        {
985            message = resourceManager.getString(
986                "validators", "SAttributeMissing");
987            throw new Error(message);
988        }
989
990        else if (_source && !_property)
991        {
992            message = resourceManager.getString(
993                "validators", "PAttributeMissing");
994            throw new Error(message);
995        }
996
997        return null;
998    }
999
1000    /**
1001     *  @private
1002     *  Main internally used function to handle validation process.
1003     */
1004    private function processValidation(
1005                        value:Object,
1006                        suppressEvents:Boolean):ValidationResultEvent
1007    {
1008        var resultEvent:ValidationResultEvent;
1009
1010        if (_enabled)
1011        {
1012            var errorResults:Array = doValidation(value);
1013
1014            resultEvent = handleResults(errorResults);
1015        }
1016        else
1017        {
1018            suppressEvents = true; // Don't send any events
1019        }
1020
1021        if (!suppressEvents)
1022        {
1023            dispatchEvent(resultEvent);
1024        }
1025
1026        return resultEvent;
1027    }
1028
1029    /**
1030     *  Executes the validation logic of this validator,
1031     *  including validating that a missing or empty value
1032     *  causes a validation error as defined by
1033     *  the value of the <code>required</code> property.
1034     *
1035     *  <p>If you create a subclass of a validator class,
1036     *  you must override this method. </p>
1037     *
1038     *  @param value Value to validate.
1039     *
1040     *  @return For an invalid result, an Array of ValidationResult objects,
1041     *  with one ValidationResult object for each field examined
1042     *  by the validator that failed validation.
1043     *
1044     *  @see mx.validators.ValidationResult
1045     *
1046     *  @langversion 3.0
1047     *  @playerversion Flash 9
1048     *  @playerversion AIR 1.1
1049     *  @productversion Flex 3
1050     */
1051    protected function doValidation(value:Object):Array
1052    {
1053        var results:Array = [];
1054
1055        var result:ValidationResult = validateRequired(value);
1056        if (result)
1057            results.push(result);
1058
1059        return results;
1060    }
1061
1062    /**
1063     *  @private
1064     *  Determines if an object is valid based on its
1065     *  <code>required</code> property.
1066     *  This is a convenience method for calling a validator from within a
1067     *  custom validation function.
1068     */
1069    private function validateRequired(value:Object):ValidationResult
1070    {
1071        if (required)
1072        {
1073            var val:String = (value != null) ? String(value) : "";
1074
1075            val = trimString(val);
1076
1077            // If the string is empty and required is set to true
1078            // then throw a requiredFieldError.
1079            if (val.length == 0)
1080            {
1081                return new ValidationResult(true, "", "requiredField",
1082                                            requiredFieldError);
1083            }
1084        }
1085
1086        return null;
1087    }
1088
1089    /**
1090     *  Returns a ValidationResultEvent from the Array of error results.
1091     *  Internally, this function takes the results from the
1092     *  <code>doValidation()</code> method and puts it into a ValidationResultEvent object.
1093     *  Subclasses, such as the RegExpValidator class,
1094     *  should override this function if they output a subclass
1095     *  of ValidationResultEvent objects, such as the RegExpValidationResult objects, and
1096     *  needs to populate the object with additional information. You never
1097     *  call this function directly, and you should rarely override it.
1098     *
1099     *  @param errorResults Array of ValidationResult objects.
1100     *
1101     *  @return The ValidationResultEvent returned by the <code>validate()</code> method.
1102     *
1103     *  @langversion 3.0
1104     *  @playerversion Flash 9
1105     *  @playerversion AIR 1.1
1106     *  @productversion Flex 3
1107     */
1108    protected function handleResults(errorResults:Array):ValidationResultEvent
1109    {
1110        var resultEvent:ValidationResultEvent;
1111
1112        if (errorResults.length > 0)
1113        {
1114            resultEvent =
1115                new ValidationResultEvent(ValidationResultEvent.INVALID);
1116            resultEvent.results = errorResults;
1117
1118            if (subFields.length > 0)
1119            {
1120                var errorFields:Object = {};
1121                var subField:String;
1122
1123                // Now we need to send valid results
1124                // for every subfield that didn't fail.
1125                var n:int;
1126                var i:int;
1127
1128                n = errorResults.length;
1129                for (i = 0; i < n; i++)
1130                {
1131                    subField = errorResults[i].subField;
1132                    if (subField)
1133                    {
1134                        errorFields[subField] = true;
1135                    }
1136                }
1137
1138                n = subFields.length;
1139                for (i = 0; i < n; i++)
1140                {
1141                    if (!errorFields[subFields[i]])
1142                    {
1143                        errorResults.push(new ValidationResult(false,subFields[i]));
1144                    }
1145                }
1146            }
1147        }
1148        else
1149        {
1150            resultEvent = new ValidationResultEvent(ValidationResultEvent.VALID);
1151        }
1152
1153        return resultEvent;
1154    }
1155
1156    //--------------------------------------------------------------------------
1157    //
1158    //  Event handlers
1159    //
1160    //--------------------------------------------------------------------------
1161
1162    /**
1163     *  @private
1164     */
1165    private function triggerHandler(event:Event):void
1166    {
1167        validate();
1168    }
1169
1170    /**
1171     *  @private
1172     */
1173    private function resourceManager_changeHandler(event:Event):void
1174    {
1175        resourcesChanged();
1176    }
1177}
1178
1179}
1180