Merge pull request #853 from echampet/onclick
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / CheckBox.cs
1 //
2 // System.Web.UI.WebControls.CheckBox.cs
3 //
4 // Author:
5 //      Dick Porter  <dick@ximian.com>
6 //
7 // Copyright (C) 2005-2010 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.Collections;
30 using System.Collections.Specialized;
31 using System.ComponentModel;
32 using System.Globalization;
33 using System.Security.Permissions;
34 using System.Web.Util;
35
36 namespace System.Web.UI.WebControls
37 {
38         // CAS
39         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
41         // attributes
42         [Designer ("System.Web.UI.Design.WebControls.CheckBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43         [DataBindingHandler ("System.Web.UI.Design.TextDataBindingHandler, " + Consts.AssemblySystem_Design)]
44         [DefaultEvent ("CheckedChanged")]
45         [DefaultProperty ("Text")]
46         [ControlValueProperty ("Checked", null)]
47         [SupportsEventValidation]
48         public class CheckBox : WebControl, IPostBackDataHandler, ICheckBoxControl
49         {
50                 string render_type;
51                 AttributeCollection common_attrs;
52                 AttributeCollection inputAttributes;
53                 StateBag inputAttributesState;
54                 AttributeCollection labelAttributes;
55                 StateBag labelAttributesState;
56                 
57                 public CheckBox () : base (HtmlTextWriterTag.Input)
58                 {
59                         render_type = "checkbox";
60                 }
61
62                 internal CheckBox (string render_type) : base (HtmlTextWriterTag.Input)
63                 {
64                         this.render_type = render_type;
65                 }
66
67                 [DefaultValue (false)]
68                 [Themeable (false)]
69                 [WebSysDescription ("")]
70                 [WebCategory ("Behavior")]
71                 public virtual bool AutoPostBack {
72                         get { return (ViewState.GetBool ("AutoPostBack", false)); }
73                         set { ViewState["AutoPostBack"] = value; }
74                 }
75
76                 [DefaultValue (false)]
77                 [Themeable (false)]
78                 [WebSysDescription ("")]
79                 [WebCategory ("Behavior")]
80                 public virtual bool CausesValidation {
81                         get { return ViewState.GetBool ("CausesValidation", false); }
82                         set { ViewState ["CausesValidation"] = value; }
83                 }
84
85                 [DefaultValue (false)]
86                 [Bindable (true, BindingDirection.TwoWay)]
87                 [Themeable (false)]
88                 [WebSysDescription ("")]
89                 [WebCategory ("Behavior")]
90                 public virtual bool Checked {
91                         get { return (ViewState.GetBool ("Checked", false)); }
92                         set { ViewState["Checked"] = value; }
93                 }
94
95                 [Browsable (false)]
96                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
97                 public AttributeCollection InputAttributes {
98                         get {
99                                 if (inputAttributes == null) {
100                                         if (inputAttributesState == null) {
101                                                 inputAttributesState = new StateBag (true);
102                                                 if (IsTrackingViewState)
103                                                         inputAttributesState.TrackViewState();
104                                         }
105                                         inputAttributes = new AttributeCollection (inputAttributesState);
106                                 }
107                                 return inputAttributes;
108                         }
109                 }
110
111                 [Browsable (false)]
112                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
113                 public AttributeCollection LabelAttributes {
114                         get {
115                                 if (labelAttributes == null) {
116                                         if (labelAttributesState == null) {
117                                                 labelAttributesState = new StateBag (true);
118                                                 if (IsTrackingViewState)
119                                                         labelAttributesState.TrackViewState();
120                                         }
121                                         labelAttributes = new AttributeCollection (labelAttributesState);
122                                 }
123                                 return labelAttributes;
124                         }
125                 }
126
127                 [DefaultValue ("")]
128                 [Bindable (true)]
129                 [Localizable (true)]
130                 [WebSysDescription ("")]
131                 [WebCategory ("Appearance")]
132                 public virtual string Text {
133                         get { return (ViewState.GetString ("Text", String.Empty)); }
134                         set { ViewState["Text"] = value; }
135                 }
136
137                 [DefaultValue (TextAlign.Right)]
138                 [WebSysDescription ("")]
139                 [WebCategory ("Appearance")]
140                 public virtual TextAlign TextAlign {
141                         get { return (TextAlign) ViewState.GetInt ("TextAlign", (int)TextAlign.Right); }
142                         set {
143                                 if (value != TextAlign.Left &&
144                                     value != TextAlign.Right) {
145                                         throw new ArgumentOutOfRangeException ("value");
146                                 }
147                                 
148                                 ViewState["TextAlign"] = value;
149                         }
150                 }
151
152                 [Themeable (false)]
153                 [DefaultValue ("")]
154                 [WebSysDescription ("")]
155                 [WebCategoryAttribute ("Behavior")]
156                 public virtual string ValidationGroup {
157                         get { return ViewState.GetString ("ValidationGroup", String.Empty); }
158                         set { ViewState["ValidationGroup"] = value; }
159                 }
160
161                 static readonly object EventCheckedChanged = new object ();
162                 [WebSysDescription ("")]
163                 [WebCategory ("Action")]
164                 public event EventHandler CheckedChanged  {
165                         add { Events.AddHandler (EventCheckedChanged, value); }
166                         remove { Events.RemoveHandler (EventCheckedChanged, value); }
167                 }
168
169                 protected virtual void OnCheckedChanged (EventArgs e)
170                 {
171                         EventHandler handler = (EventHandler)Events[EventCheckedChanged];
172                         
173                         if (handler != null)
174                                 handler (this, e);
175                 }
176
177                 internal virtual string NameAttribute {
178                         get { return (this.UniqueID); }
179                 }
180                 
181                 protected override void LoadViewState (object savedState)
182                 {
183                         if (savedState == null) {
184                                 base.LoadViewState (null);
185                                 return;
186                         }
187
188                         Triplet saved = (Triplet) savedState;
189                         base.LoadViewState (saved.First);
190
191                         if (saved.Second != null) {
192                                 if (inputAttributesState == null) {
193                                         inputAttributesState = new StateBag(true);
194                                         inputAttributesState.TrackViewState ();
195                                 }
196                                 inputAttributesState.LoadViewState (saved.Second);
197                         }
198
199                         if (saved.Third != null) {
200                                 if (labelAttributesState == null) {
201                                         labelAttributesState = new StateBag(true);
202                                         labelAttributesState.TrackViewState ();
203                                 }
204                                 labelAttributesState.LoadViewState (saved.Third);
205                         }
206                 }
207
208                 protected override object SaveViewState ()
209                 {
210                         object baseView = base.SaveViewState ();
211                         object inputAttrView = null;
212                         object labelAttrView = null;
213
214                         if (inputAttributesState != null)
215                                 inputAttrView = inputAttributesState.SaveViewState ();
216
217                         if (labelAttributesState != null)
218                                 labelAttrView = labelAttributesState.SaveViewState ();
219
220                         if (baseView == null && inputAttrView == null && labelAttrView == null)
221                                 return null;
222
223                         return new Triplet (baseView, inputAttrView, labelAttrView);            
224                 }
225
226                 protected override void TrackViewState ()
227                 {
228                         base.TrackViewState();
229                         if (inputAttributesState != null)
230                                 inputAttributesState.TrackViewState ();
231                         if (labelAttributesState != null)
232                                 labelAttributesState.TrackViewState ();
233                 }
234
235                 protected internal override void OnPreRender (EventArgs e)
236                 {
237                         base.OnPreRender (e);
238                         Page page = Page;
239                         
240                         if (page != null && IsEnabled) {
241                                 page.RegisterRequiresPostBack (this);
242                                 page.RegisterEnabledControl (this);
243                         }
244                 }
245
246                 static bool IsInputOrCommonAttr (string attname)
247                 {
248                         attname = attname.ToUpper (Helpers.InvariantCulture);
249                         switch (attname) {
250                                 case "VALUE":
251                                 case "CHECKED":
252                                 case "SIZE":
253                                 case "MAXLENGTH":
254                                 case "SRC":
255                                 case "ALT":
256                                 case "USEMAP":
257                                 case "DISABLED":
258                                 case "READONLY":
259                                 case "ACCEPT":
260                                 case "ACCESSKEY":
261                                 case "TABINDEX":
262                                 case "ONFOCUS":
263                                 case "ONBLUR":
264                                 case "ONSELECT":
265                                 case "ONCHANGE":
266                                 case "ONCLICK":
267                                 case "ONDBLCLICK":
268                                 case "ONMOUSEDOWN":
269                                 case "ONMOUSEUP":
270                                 case "ONMOUSEOVER":
271                                 case "ONMOUSEMOVE":
272                                 case "ONMOUSEOUT":
273                                 case "ONKEYPRESS":
274                                 case "ONKEYDOWN":
275                                 case "ONKEYUP":
276                                         return true;
277                                 default:
278                                         return false;
279                         }
280                 }
281
282                 bool AddAttributesForSpan (HtmlTextWriter writer)
283                 {
284                         if (HasAttributes) {
285                                 AttributeCollection attributes = Attributes;
286                                 ICollection k = attributes.Keys;
287                                 string [] keys = new string [k.Count];
288                                 k.CopyTo (keys, 0);
289                                 foreach (string key in keys) {
290                                         if (!IsInputOrCommonAttr (key))
291                                                 continue;
292                                         if (common_attrs == null)
293                                                 common_attrs = new AttributeCollection (new StateBag ());
294                                         common_attrs [key] = Attributes [key];
295                                         attributes.Remove (key);
296                                 }
297                         
298                                 if (attributes.Count > 0) {
299                                         attributes.AddAttributes (writer);
300                                         return true;
301                                 }
302                         }
303                         
304                         return false;
305                 }
306
307                 protected internal override void Render (HtmlTextWriter w)
308                 {
309                         Page page = Page;
310                         if (page != null) {
311                                 page.VerifyRenderingInServerForm (this);
312                                 page.ClientScript.RegisterForEventValidation (UniqueID);
313                         }
314                         
315                         bool need_span = ControlStyleCreated && !ControlStyle.IsEmpty;
316                         bool enabled = IsEnabled;
317                         if (!enabled) {
318                                 if (!RenderingCompatibilityLessThan40)
319                                         ControlStyle.PrependCssClass (DisabledCssClass);
320                                 else
321                                         w.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled", false);
322                                 need_span = true;
323                         }
324
325                         if (need_span) {
326                                 AddDisplayStyleAttribute (w);
327                                 ControlStyle.AddAttributesToRender (w, this);
328                         }
329                         
330                         string tt = ToolTip;
331                         if (tt != null && tt.Length > 0){
332                                 w.AddAttribute ("title", tt);
333                                 need_span = true;
334                         }
335
336                         if (HasAttributes && AddAttributesForSpan (w))
337                                 need_span = true;
338                         
339                         if (need_span)
340                                 w.RenderBeginTag (HtmlTextWriterTag.Span);
341
342                         TextAlign align = TextAlign;
343                         if (align == TextAlign.Right) {
344                                 RenderInput (w, enabled);
345                                 RenderLabel (w);
346                         } else {
347                                 RenderLabel (w);
348                                 RenderInput (w, enabled);
349                         }
350
351                         if (need_span)
352                                 w.RenderEndTag ();
353                 }
354
355                 void RenderInput (HtmlTextWriter w, bool enabled)
356                 {
357                         if (ClientID != null && ClientID.Length > 0)
358                                 w.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
359                         w.AddAttribute (HtmlTextWriterAttribute.Type, render_type);
360                         string nameAttr = NameAttribute;
361                         if (nameAttr != null && nameAttr.Length > 0)
362                                 w.AddAttribute (HtmlTextWriterAttribute.Name, nameAttr);
363                         InternalAddAttributesToRender (w, enabled);
364                         AddAttributesToRender (w);
365                         
366                         if (Checked)
367                                 w.AddAttribute (HtmlTextWriterAttribute.Checked, "checked", false);
368
369                         if (AutoPostBack) {
370                                 Page page = Page;
371                                 string onclick = page != null ? page.ClientScript.GetPostBackEventReference (GetPostBackOptions (), true) : String.Empty;
372                                 onclick = String.Concat ("setTimeout('", onclick.Replace ("\\", "\\\\").Replace ("'", "\\'"), "', 0)");
373                                 if (common_attrs != null && common_attrs ["onclick"] != null) {
374                                         onclick = ClientScriptManager.EnsureEndsWithSemicolon (common_attrs ["onclick"]) + onclick;
375                                         common_attrs.Remove ("onclick");
376                                 }
377                                 w.AddAttribute (HtmlTextWriterAttribute.Onclick, onclick);
378                         }
379
380                         if (AccessKey.Length > 0)
381                                 w.AddAttribute (HtmlTextWriterAttribute.Accesskey, AccessKey);
382
383                         if (TabIndex != 0)
384                                 w.AddAttribute (HtmlTextWriterAttribute.Tabindex,
385                                                          TabIndex.ToString (NumberFormatInfo.InvariantInfo));
386
387                         if (common_attrs != null)
388                                 common_attrs.AddAttributes (w);
389
390                         if (inputAttributes != null)
391                                 inputAttributes.AddAttributes (w);
392                         
393                         w.RenderBeginTag (HtmlTextWriterTag.Input);
394                         w.RenderEndTag ();
395                 }
396
397                 void RenderLabel (HtmlTextWriter w)
398                 {
399                         string text = Text;
400                         if (text.Length > 0) {
401                                 if (labelAttributes != null)
402                                         labelAttributes.AddAttributes (w);
403                                 w.AddAttribute (HtmlTextWriterAttribute.For, ClientID);
404                                 w.RenderBeginTag (HtmlTextWriterTag.Label);
405                                 w.Write (text);
406                                 w.RenderEndTag ();
407                         }
408                 }
409
410                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
411                 {
412                         if (!IsEnabled)
413                                 return false;
414
415                         string postedValue = postCollection[postDataKey];
416                         bool postedBool = ((postedValue != null) &&
417                                            (postedValue.Length > 0));
418                         
419                         if (Checked != postedBool) {
420                                 Checked = postedBool;
421                                 return (true);
422                         }
423
424                         return (false);
425                 }
426
427                 protected virtual void RaisePostDataChangedEvent ()
428                 {
429                         ValidateEvent (UniqueID, String.Empty);
430                         if (CausesValidation) {
431                                 Page page = Page;
432                                 if (page != null)
433                                         page.Validate (ValidationGroup);
434                         }
435                         
436                         OnCheckedChanged (EventArgs.Empty);
437                 }
438
439                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
440                 {
441                         return LoadPostData (postDataKey, postCollection);
442                 }
443                 
444                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
445                 {
446                         RaisePostDataChangedEvent ();
447                 }
448
449                 PostBackOptions GetPostBackOptions ()
450                 {
451                         PostBackOptions options = new PostBackOptions (this);
452                         options.ActionUrl = null;
453                         options.ValidationGroup = null;
454                         options.Argument = String.Empty;
455                         options.RequiresJavaScriptProtocol = false;
456                         options.ClientSubmit = true;
457
458                         Page page = Page;
459                         options.PerformValidation = CausesValidation && page != null && page.AreValidatorsUplevel (ValidationGroup);
460                         if (options.PerformValidation)
461                                 options.ValidationGroup = ValidationGroup;
462
463                         return options;
464                 }
465
466                 protected override void AddAttributesToRender (HtmlTextWriter writer)
467                 {
468                 }
469
470                 internal virtual void InternalAddAttributesToRender (HtmlTextWriter w, bool enabled)
471                 {
472                         if (!enabled)
473                                 w.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled", false);
474                 }
475         }
476 }