2010-06-21 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / BaseValidator.cs
1 //
2 // System.Web.UI.WebControls.BaseValidator
3 //
4 // Authors:
5 //      Chris Toshok (toshok@novell.com)
6 //
7 // (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Web.Configuration;
30 using System.ComponentModel;
31 using System.Drawing;
32 using System.Reflection;
33 using System.Collections;
34 using System.Security.Permissions;
35
36 namespace System.Web.UI.WebControls {
37
38         // CAS
39         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
41         // attributes
42         [DefaultProperty("ErrorMessage")]
43         [Designer("System.Web.UI.Design.WebControls.BaseValidatorDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
44         public abstract class BaseValidator : Label, IValidator
45         {
46                 bool render_uplevel;
47                 bool valid;
48                 Color forecolor;
49
50                 protected BaseValidator ()
51                 {
52                         this.valid = true;
53                         this.ForeColor = Color.Red;
54                 }
55
56                 // New in NET1.1 sp1
57                 [Browsable(false)]
58 #if ONLY_1_1
59                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
60 #endif          
61                 [EditorBrowsable(EditorBrowsableState.Never)]
62                 public override string AssociatedControlID {
63                         get {
64                                 return base.AssociatedControlID;
65                         }
66                         set {
67                                 base.AssociatedControlID = value;
68                         }
69                 }
70
71 #if NET_2_0
72                 [Themeable (false)]
73                 [DefaultValue ("")]
74                 public virtual string ValidationGroup {
75                         get { return ViewState.GetString ("ValidationGroup", String.Empty); }
76                         set { ViewState["ValidationGroup"] = value; }
77                 }
78
79                 [Themeable (false)]
80                 [DefaultValue (false)]
81                 public bool SetFocusOnError {
82                         get { return ViewState.GetBool ("SetFocusOnError", false); }
83                         set { ViewState["SetFocusOnError"] = value; }
84                 }
85
86                 /* listed in corcompare */
87                 [MonoTODO("Why override?")]
88                 [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
89                 [DefaultValue ("")]
90                 public override string Text 
91                 {
92                         get { return base.Text; }
93                         set { base.Text = value; }
94                 }
95 #endif
96
97 #if NET_2_0
98                 [IDReferenceProperty (typeof (Control))]
99                 [Themeable (false)]
100 #endif
101                 [TypeConverter(typeof(System.Web.UI.WebControls.ValidatedControlConverter))]
102                 [DefaultValue("")]
103                 [WebSysDescription ("")]
104                 [WebCategory ("Behavior")]
105                 public string ControlToValidate {
106                         get { return ViewState.GetString ("ControlToValidate", String.Empty); }
107                         set { ViewState ["ControlToValidate"] = value; }
108                 }
109
110 #if NET_2_0
111                 [Themeable (false)]
112 #endif
113 #if ONLY_1_1            
114                 [Bindable(true)]
115 #endif          
116                 [DefaultValue(ValidatorDisplay.Static)]
117                 [WebSysDescription ("")]
118                 [WebCategory ("Appearance")]
119                 public ValidatorDisplay Display {
120                         get { return (ValidatorDisplay)ViewState.GetInt ("Display", (int)ValidatorDisplay.Static); }
121                         set { ViewState ["Display"] = (int)value; }
122                 }
123
124 #if NET_2_0
125                 [Themeable (false)]
126 #endif
127                 [DefaultValue(true)]
128                 [WebSysDescription ("")]
129                 [WebCategory ("Behavior")]
130                 public bool EnableClientScript {
131                         get { return ViewState.GetBool ("EnableClientScript", true); }
132                         set { ViewState ["EnableClientScript"] = value; }
133                 }
134
135                 public override bool Enabled {
136                         get { return ViewState.GetBool ("BaseValidatorEnabled", true); }
137                         set { ViewState ["BaseValidatorEnabled"] = value; }
138                 }
139
140 #if NET_2_0
141                 [Localizable (true)]
142 #endif
143 #if ONLY_1_1
144                 [Bindable(true)]
145 #endif          
146                 [DefaultValue("")]
147                 [WebSysDescription ("")]
148                 [WebCategory ("Appearance")]
149 #if NET_2_0
150                 public
151 #else
152                 public virtual
153 #endif
154                 string ErrorMessage {
155                         get { return ViewState.GetString ("ErrorMessage", String.Empty); }
156                         set { ViewState ["ErrorMessage"] = value; }
157                 }
158
159                 [DefaultValue(typeof (Color), "Red")]
160                 public override Color ForeColor {
161                         get { return forecolor; }
162                         set {
163                                 forecolor = value;
164                                 base.ForeColor = value;
165                         }
166                 }
167
168                 [Browsable(false)]
169                 [DefaultValue(true)]
170 #if NET_2_0
171                 [Themeable (false)]
172 #endif
173                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
174                 [WebSysDescription ("")]
175                 [WebCategory ("Misc")]
176 #if NET_2_0
177                 public
178 #else
179                 public virtual
180 #endif
181                 bool IsValid {
182                         get { return valid; }
183                         set { valid = value; }
184                 }
185
186                 protected bool PropertiesValid {
187                         get {
188                                 Control control = NamingContainer.FindControl (ControlToValidate);
189                                 if (control == null)
190                                         return false;
191                                 else
192                                         return true;
193                         }
194                 }
195
196                 protected bool RenderUplevel {
197                         get { return render_uplevel; }
198                 }
199
200                 internal bool GetRenderUplevel ()
201                 {
202                         return render_uplevel;
203                 }
204
205                 protected override void AddAttributesToRender (HtmlTextWriter writer)
206                 {
207                         /* if we're rendering uplevel, add our attributes */
208                         if (render_uplevel) {
209                                 /* force an ID here if we weren't assigned one */
210                                 if (ID == null)
211                                         writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
212
213                                 if (ControlToValidate != String.Empty)
214 #if NET_2_0
215                                         RegisterExpandoAttribute (ClientID, "controltovalidate", GetControlRenderID (ControlToValidate));
216 #else
217                                         writer.AddAttribute ("controltovalidate", GetControlRenderID (ControlToValidate));
218 #endif
219
220                                 if (ErrorMessage != String.Empty)
221 #if NET_2_0
222                                         RegisterExpandoAttribute (ClientID, "errormessage", ErrorMessage, true);
223 #else
224                                         writer.AddAttribute ("errormessage", ErrorMessage);
225
226                                 if (Text != String.Empty)
227                                         writer.AddAttribute ("text", Text);
228 #endif
229
230 #if NET_2_0
231                                 if (ValidationGroup != String.Empty)
232                                         RegisterExpandoAttribute (ClientID, "validationGroup", ValidationGroup, true);
233
234                                 if (SetFocusOnError)
235                                         RegisterExpandoAttribute (ClientID, "focusOnError", "t");
236 #endif
237                                 if (!Enabled)
238 #if NET_2_0
239                                         RegisterExpandoAttribute (ClientID, "enabled", "False");
240 #else
241                                         writer.AddAttribute ("enabled", "false", false);
242 #endif
243
244 #if NET_2_0
245                                 if (Enabled && !IsValid) {
246                                         RegisterExpandoAttribute (ClientID, "isvalid", "False");
247 #else
248                                 if (!IsValid) {
249                                         writer.AddAttribute ("isvalid", "false", false);
250 #endif
251                                 }
252                                 else {
253                                         if (Display == ValidatorDisplay.Static)
254                                                 writer.AddStyleAttribute ("visibility", "hidden");
255                                         else
256                                                 writer.AddStyleAttribute ("display", "none");
257                                 }
258
259                                 if (Display != ValidatorDisplay.Static)
260 #if NET_2_0
261                                         RegisterExpandoAttribute (ClientID, "display", Display.ToString ());
262 #else
263                                         writer.AddAttribute ("display", Display.ToString());
264 #endif
265                         }
266
267                         base.AddAttributesToRender (writer);
268                 }
269
270 #if NET_2_0
271                 internal void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue) {
272                         RegisterExpandoAttribute (controlId, attributeName, attributeValue, false);
273                 }
274
275                 internal void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue, bool encode) {
276                         if (Page.ScriptManager != null)
277                                 Page.ScriptManager.RegisterExpandoAttributeExternal (this, controlId, attributeName, attributeValue, encode);
278                         else
279                                 Page.ClientScript.RegisterExpandoAttribute (controlId, attributeName, attributeValue, encode);
280                 }
281 #endif
282
283                 protected void CheckControlValidationProperty (string name, string propertyName)
284                 {
285                         Control control = NamingContainer.FindControl (name);
286                         PropertyDescriptor prop = null;
287
288                         if (control == null)
289                                 throw new HttpException (String.Format ("Unable to find control id '{0}'.", name));
290
291                         prop = BaseValidator.GetValidationProperty (control);
292                         if (prop == null)
293                                 throw new HttpException (String.Format ("Unable to find ValidationProperty attribute '{0}' on control '{1}'", propertyName, name));
294                 }
295
296                 protected virtual bool ControlPropertiesValid ()
297                 {
298                         if (ControlToValidate.Length == 0) {
299                                 throw new HttpException (String.Format ("ControlToValidate property of '{0}' cannot be blank.", ID));
300                         }
301
302                         CheckControlValidationProperty (ControlToValidate, "");
303
304                         return true;
305                 }
306
307                 protected virtual bool DetermineRenderUplevel ()
308                 {
309                         if (!EnableClientScript)
310                                 return false;
311 #if TARGET_J2EE
312                         if (HttpContext.Current == null)
313                                 return false;
314
315                         return (
316                                 /* From someplace on the web: "JavaScript 1.2
317                                  * and later (also known as ECMAScript) has
318                                  * built-in support for regular
319                                  * expressions" */
320                                 ((Page.Request.Browser.EcmaScriptVersion.Major == 1
321                                   && Page.Request.Browser.EcmaScriptVersion.Minor >= 2)
322                                  || (Page.Request.Browser.EcmaScriptVersion.Major > 1))
323
324                                 /* document.getElementById, .getAttribute,
325                                  * etc, are all DOM level 1.  I don't think we
326                                  * use anything in level 2.. */
327                                 && Page.Request.Browser.W3CDomVersion.Major >= 1);
328 #else
329                         return UplevelHelper.IsUplevel (
330                                 System.Web.Configuration.HttpCapabilitiesBase.GetUserAgentForDetection (HttpContext.Current.Request));
331 #endif
332                 }
333
334                 protected abstract bool EvaluateIsValid ();
335
336                 protected string GetControlRenderID (string name)
337                 {
338                         Control control = NamingContainer.FindControl (name);
339                         if (control == null)
340                                 return null;
341
342                         return control.ClientID;
343                 }
344
345                 protected string GetControlValidationValue (string name)
346                 {
347                         Control control = NamingContainer.FindControl (name);
348
349                         if (control == null)
350                                 return null;
351
352                         PropertyDescriptor prop = BaseValidator.GetValidationProperty (control);
353                         if (prop == null)
354                                 return null;
355
356                         object o = prop.GetValue (control);
357
358                         if (o == null)
359                                 return String.Empty;
360                         
361                         if (o is ListItem)
362                                 return ((ListItem) o).Value;
363                         
364                         return o.ToString ();
365                 }
366
367                 public static PropertyDescriptor GetValidationProperty (object o)
368                 {
369                         PropertyDescriptorCollection props;
370                         System.ComponentModel.AttributeCollection col;
371
372                         props = TypeDescriptor.GetProperties (o);
373                         col = TypeDescriptor.GetAttributes (o);
374
375                         foreach (Attribute at in col) {
376                                 ValidationPropertyAttribute vpa = at as ValidationPropertyAttribute;
377                                 if (vpa != null && vpa.Name != null)
378                                         return props[vpa.Name];
379                         }
380
381                         return null;
382                 }
383
384 #if NET_2_0
385                 protected internal
386 #else           
387                 protected
388 #endif          
389                 override void OnInit (EventArgs e)
390                 {
391                         /* according to an msdn article, this is done here */
392                         if (Page != null) {
393                                 Page.Validators.Add (this);
394
395 #if NET_2_0
396                                 Page.GetValidators (ValidationGroup).Add (this);
397 #endif
398                         }
399                         base.OnInit (e);
400                 }
401
402                 bool pre_render_called = false;
403
404 #if NET_2_0
405                 protected internal
406 #else
407                 protected
408 #endif          
409                 override void OnPreRender (EventArgs e)
410                 {
411                         base.OnPreRender (e);
412
413                         pre_render_called = true;
414                         
415                         ControlPropertiesValid ();
416
417                         render_uplevel = DetermineRenderUplevel ();
418                         if (render_uplevel) {
419                                 RegisterValidatorCommonScript ();
420                         }
421                 }
422
423 #if NET_2_0
424                 protected internal
425 #else           
426                 protected
427 #endif          
428                 override void OnUnload (EventArgs e)
429                 {
430                         /* according to an msdn article, this is done here */
431                         if (Page != null) {
432                                 Page.Validators.Remove (this);
433
434 #if NET_2_0
435                                 if (ValidationGroup != "")
436                                         Page.GetValidators (ValidationGroup).Remove (this);
437 #endif
438
439                         }
440                         base.OnUnload (e);
441                 }
442
443                 protected void RegisterValidatorCommonScript ()
444                 {
445 #if NET_2_0
446                         if (Page.ScriptManager != null) {
447                                 Page.ScriptManager.RegisterClientScriptResourceExternal (this, typeof (BaseValidator), "WebUIValidation_2.0.js");
448                                 Page.ScriptManager.RegisterClientScriptBlockExternal (this, typeof (BaseValidator), "ValidationInitializeScript", Page.ValidationInitializeScript, true);
449                                 Page.ScriptManager.RegisterOnSubmitStatementExternal (this, typeof (BaseValidator), "ValidationOnSubmitStatement", Page.ValidationOnSubmitStatement);
450                                 Page.ScriptManager.RegisterStartupScriptExternal (this, typeof (BaseValidator), "ValidationStartupScript", Page.ValidationStartupScript, true);
451                         }
452                         else
453 #endif
454                         if (!Page.ClientScript.IsClientScriptIncludeRegistered (typeof (BaseValidator), "Mono-System.Web-ValidationClientScriptBlock"))
455                         {
456                                 Page.ClientScript.RegisterClientScriptInclude (typeof (BaseValidator), "Mono-System.Web-ValidationClientScriptBlock",
457                                         Page.ClientScript.GetWebResourceUrl (typeof (BaseValidator), 
458 #if NET_2_0
459                                                 "WebUIValidation_2.0.js"));
460                                 Page.ClientScript.RegisterClientScriptBlock (typeof (BaseValidator), "Mono-System.Web-ValidationClientScriptBlock.Initialize", Page.ValidationInitializeScript, true);
461                                 Page.ClientScript.RegisterOnSubmitStatement (typeof (BaseValidator), "Mono-System.Web-ValidationOnSubmitStatement", Page.ValidationOnSubmitStatement);
462                                 Page.ClientScript.RegisterStartupScript (typeof (BaseValidator), "Mono-System.Web-ValidationStartupScript", Page.ValidationStartupScript, true);
463 #else           
464                                                 "WebUIValidation.js"));
465
466                                 Page.ClientScript.RegisterOnSubmitStatement ("Mono-System.Web-ValidationOnSubmitStatement",
467                                                                              "if (!ValidatorOnSubmit()) return false;");
468                                 Page.ClientScript.RegisterStartupScript ("Mono-System.Web-ValidationStartupScript",
469                                                                          "<script language=\"JavaScript\">\n" + 
470                                                                          "<!--\n" + 
471                                                                          "var Page_ValidationActive = false;\n" + 
472                                                                          "ValidatorOnLoad();\n" +
473                                                                          "\n" + 
474                                                                          "function ValidatorOnSubmit() {\n" + 
475                                                                          "        if (Page_ValidationActive) {\n" + 
476                                                                          "                if (!ValidatorCommonOnSubmit())\n" +
477                                                                          "                        return Page_ClientValidate ();\n" +
478                                                                          "        }\n" + 
479                                                                          "        return true;\n" + 
480                                                                          "}\n" + 
481                                                                          "// -->\n" + 
482                                                                          "</script>\n");
483 #endif
484                         }
485                 }
486
487                 protected virtual void RegisterValidatorDeclaration ()
488                 {
489 #if NET_2_0
490                         if (Page.ScriptManager != null) {
491                                 Page.ScriptManager.RegisterArrayDeclarationExternal (this, "Page_Validators", String.Concat ("document.getElementById ('", ClientID, "')"));
492                                 Page.ScriptManager.RegisterStartupScriptExternal (this, typeof (BaseValidator), ClientID + "DisposeScript",
493 @"
494 document.getElementById('" + ClientID + @"').dispose = function() {
495     Array.remove(Page_Validators, document.getElementById('" + ClientID + @"'));
496 }
497 ", true);
498                         }
499                         else
500 #endif
501                         Page.ClientScript.RegisterArrayDeclaration ("Page_Validators",
502                                                                     String.Concat ("document.getElementById ('", ClientID, "')"));
503                 }
504
505 #if NET_2_0
506                 protected internal
507 #else           
508                 protected
509 #endif          
510                 override void Render (HtmlTextWriter writer)
511                 {
512 #if NET_2_0
513                         if (!Enabled && !EnableClientScript)
514                                 return;
515 #endif
516                         if (render_uplevel) {
517                                 /* according to an msdn article, this is done here */
518                                 RegisterValidatorDeclaration ();
519                         }
520
521                         bool render_tags = false;
522                         bool render_text = false;
523                         bool render_nbsp = false;
524                         bool v = IsValid;
525
526                         if (!pre_render_called) {
527                                 render_tags = true;
528                                 render_text = true;
529                         }
530                         else if (render_uplevel) {
531                                 render_tags = true;
532 #if NET_2_0
533                                 render_text = Display != ValidatorDisplay.None;
534 #else
535                                 if (Display != ValidatorDisplay.None)
536                                         render_text = !v || Display == ValidatorDisplay.Dynamic;
537 #endif
538                         }
539                         else {
540                                 if (Display != ValidatorDisplay.None) {
541                                         render_tags = !v;
542                                         render_text = !v;
543                                         render_nbsp = v && Display == ValidatorDisplay.Static;
544                                 }
545                         }
546
547                         if (render_tags) {
548                                 AddAttributesToRender (writer);
549                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
550                         }
551
552                         if (render_text || render_nbsp) {
553                                 string text;
554                                 if (render_text) {
555                                         text = Text;
556                                         if (text == "")
557                                                 text = ErrorMessage;
558                                 } else {
559                                         text = "&nbsp;";
560                                 }
561
562                                 writer.Write (text);
563                         }
564
565
566                         if (render_tags) {
567                                 writer.RenderEndTag ();
568                         }
569                 }
570
571                 /* the docs say "public sealed" here */
572 #if NET_2_0
573                 public
574 #else
575                 public virtual
576 #endif
577                 void Validate ()
578                 {
579                         if (Enabled && Visible)
580                                 IsValid = ControlPropertiesValid () && EvaluateIsValid ();
581                         else
582                                 IsValid = true;
583                 }
584         }
585
586 }