Fixing an issue with output parameters that are of type IntPtr
[castle.git] / MonoRail / Castle.MonoRail.Framework / Helpers / FormHelper.cs
blob4138c50f11a7666f64addd8d7905936aa2588145
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.MonoRail.Framework.Helpers
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Collections.Specialized;
21 using System.IO;
22 using System.Text;
23 using Configuration;
24 using Services;
25 using HtmlTextWriter = System.Web.UI.HtmlTextWriter;
27 using Castle.Core;
28 using Castle.Core.Logging;
29 using Castle.MonoRail.Framework;
30 using Castle.MonoRail.Framework.Helpers.ValidationStrategy;
31 using Castle.MonoRail.Framework.Internal;
32 using Castle.Components.Validator;
35 /// <summary>
36 /// The FormHelper allows you to output html input elements using the
37 /// conventions necessary to use the DataBinder on the server side. Ultimately it
38 /// allows you do to a bi-directional binding -- if used properly.
39 /// </summary>
40 ///
41 /// <seealso xref="DataBindAttribute"/>
42 ///
43 /// <example>
44 /// Using simple values:
45 /// <para>On the controller:</para>
46 ///
47 /// <code>
48 /// public void MyAction()
49 /// {
50 /// PropertyBag["name"] = "John Doe";
51 /// }
52 /// </code>
53 ///
54 /// <para>On the view (using NVelocity syntax)</para>
55 ///
56 /// <code lang="none">
57 /// $Form.TextField('name') // Renders an input text with value "John Doe"
58 /// </code>
59 ///
60 /// <para>
61 /// Using complex objects:
62 /// </para>
63 ///
64 /// <code>
65 /// public void MyAction()
66 /// {
67 /// PropertyBag["user"] = new User("John Doe");
68 /// }
69 /// </code>
70 ///
71 /// <para>On the view (using NVelocity syntax)</para>
72 ///
73 /// <code lang="none">
74 /// $Form.TextField('user.name') // Renders an input text with value "John Doe"
75 /// </code>
76 /// </example>
77 ///
78 /// <remarks>
79 /// <b>Elements generation</b> <br/>
80 /// <para>
81 /// <list type="table">
82 /// <item>
83 /// <term>Buttons</term>
84 /// <description>
85 /// <see cref="Submit(string)"/> <br/>
86 /// <see cref="Button(string)" /> <br/>
87 /// <see cref="ButtonElement(string)" />
88 /// </description>
89 /// </item>
90 ///
91 /// <item>
92 /// <term>Select</term>
93 /// <description>
94 /// <see cref="Select(string,IEnumerable)" />
95 /// </description>
96 /// </item>
97 ///
98 /// <item>
99 /// <term>Text area</term>
100 /// <description>
101 /// <see cref="TextArea(string)" />
102 /// </description>
103 /// </item>
104 ///
105 /// <item>
106 /// <term>Hidden field</term>
107 /// <description>
108 /// <see cref="HiddenField(string)" />
109 /// </description>
110 /// </item>
111 ///
112 /// <item>
113 /// <term>Checkbox field</term>
114 /// <description>
115 /// <see cref="CheckboxField(string)" /> <br/>
116 /// <see cref="CreateCheckboxList(string,IEnumerable)" />
117 /// </description>
118 /// </item>
119 ///
120 /// <item>
121 /// <term>Radio field</term>
122 /// <description>
123 /// <see cref="RadioField(string,object)" />
124 /// </description>
125 /// </item>
126 ///
127 /// <item>
128 /// <term>File upload</term>
129 /// <description>
130 /// <see cref="FileField(string)" />
131 /// </description>
132 /// </item>
133 ///
134 /// <item>
135 /// <term>Text field</term>
136 /// <description>
137 /// <see cref="TextField(string)" /> <br/>
138 /// <see cref="TextFieldValue(string, object)"/> <br/>
139 /// <see cref="NumberField(string)" /> <br/>
140 /// <see cref="NumberFieldValue(string, object)"/>
141 /// </description>
142 /// </item>
143 ///
144 /// <item>
145 /// <term>Password field</term>
146 /// <description>
147 /// <see cref="PasswordField(string)" /> <br/>
148 /// <see cref="PasswordNumberField(string)" />
149 /// </description>
150 /// </item>
151 ///
152 /// <item>
153 /// <term>Labels</term>
154 /// <description>
155 /// <see cref="LabelFor(string,string)" /> <br/>
156 /// <see cref="LabelFor(string,string,IDictionary)"/>
157 /// </description>
158 /// </item>
159 ///
160 /// </list>
161 /// </para>
162 ///
163 /// <para>
164 /// <b>FormValidation</b> <br/>
165 /// The following operations are related to the Form Validation support:
166 /// </para>
167 ///
168 /// <list type="table">
169 /// <item>
170 /// <term><see cref="FormTag(IDictionary)"/> and <see cref="EndFormTag"/> </term>
171 /// <description>Opens/close the form tag. They are required to use the automatic form validation</description>
172 /// </item>
173 /// <item>
174 /// <term><see cref="AbstractFormRelatedHelper.DisableValidation"/> </term>
175 /// <description>Disables validation altogether</description>
176 /// </item>
177 /// <item>
178 /// <term><see cref="UseWebValidatorProvider"/> </term>
179 /// <description>Sets a custom Browser validator provider</description>
180 /// </item>
181 /// <item>
182 /// <term><see cref="UsePrototypeValidation"/> </term>
183 /// <description>Configures the helper to use the prototype easy field validation. Must be invoked before FormTag</description>
184 /// </item>
185 /// <item>
186 /// <term><see cref="UsefValidate"/> </term>
187 /// <description>Configures the helper to use the fValidate. Deprecated.</description>
188 /// </item>
189 /// <item>
190 /// <term><see cref="UseZebdaValidation"/> </term>
191 /// <description>Configures the helper to use the Zebda. Must be invoked before FormTag</description>
192 /// </item>
193 /// </list>
194 ///
195 /// <para>
196 /// <b>Mask support</b>. <br/>
197 /// For most elements, you can use
198 /// the entries <c>mask</c> and optionally <c>mask_separator</c> to define a
199 /// mask for your inputs. Kudos to mordechai Sandhaus - 52action.com
200 /// </para>
201 ///
202 /// <para>
203 /// For example: mask='2,5',mask_separator='/' will mask the content to '12/34/1234'
204 /// </para>
205 /// </remarks>
206 public class FormHelper : AbstractFormRelatedHelper, IServiceEnabledComponent
208 private int formCount;
209 private string currentFormId;
211 #region Constructors
213 /// <summary>
214 /// Initializes a new instance of the <see cref="FormHelper"/> class.
215 /// </summary>
216 public FormHelper()
218 Initialize();
221 /// <summary>
222 /// Initializes a new instance of the <see cref="FormHelper"/> class.
223 /// setting the Controller, Context and ControllerContext.
224 /// </summary>
225 /// <param name="engineContext">The engine context.</param>
226 public FormHelper(IEngineContext engineContext) : base(engineContext)
228 Initialize();
231 private void Initialize()
233 ValidatorRegistry = new CachedValidationRegistry();
234 ValidatorRunner = new ValidatorRunner(false, ValidatorRegistry);
235 ValidatorProvider = new PrototypeWebValidator();
238 #endregion
240 #region IServiceEnabledComponent implementation
242 /// <summary>
243 /// Invoked by the framework in order to give a chance to
244 /// obtain other services
245 /// </summary>
246 /// <param name="provider">The service proviver</param>
247 public virtual void Service(IServiceProvider provider)
249 ILoggerFactory loggerFactory = (ILoggerFactory)provider.GetService(typeof(ILoggerFactory));
251 if (loggerFactory != null)
253 logger = loggerFactory.Create(typeof(FormHelper));
256 IMonoRailConfiguration config = (IMonoRailConfiguration)provider.GetService(typeof(IMonoRailConfiguration));
258 if (config != null)
260 LibraryConfiguration jsLibConfig = config.JSGeneratorConfiguration.DefaultLibrary;
262 if (jsLibConfig != null)
264 if (jsLibConfig.BrowserValidatorProvider != null)
266 ValidatorProvider = (IBrowserValidatorProvider)
267 Activator.CreateInstance(jsLibConfig.BrowserValidatorProvider);
272 ValidatorRegistry = (IValidatorRegistry)provider.GetService(typeof(IValidatorRegistry));
274 if (ValidatorRegistry != null)
276 ValidatorRunner = new ValidatorRunner(false, ValidatorRegistry);
278 else
280 ValidatorRunner = new ValidatorRunner(false, new CachedValidationRegistry());
284 #endregion
286 /// <summary>
287 /// Renders a Javascript library inside a single script tag.
288 /// </summary>
289 /// <returns></returns>
290 public virtual string InstallScripts()
292 return RenderScriptBlockToSource("/MonoRail/Files/FormHelperScript");
295 #region FormTag related
297 /// <summary>
298 /// Creates a form tag based on the parameters.
299 /// <para>
300 /// Javascript validation can also be bound to
301 /// the form and|or elements nested as long as the helper is
302 /// able to reach the <see cref="Type"/> of the object used on your view code
303 /// </para>
304 /// <para>
305 /// The action attribute generation will use <see cref="UrlHelper"/>
306 /// </para>
307 /// </summary>
308 ///
309 /// <seealso cref="DefaultUrlBuilder.BuildUrl(UrlInfo,IDictionary)"/>
310 ///
311 /// <example>
312 ///
313 /// <code lang="none">
314 /// $Form.FormTag("%{action='Save',id='productform'}")
315 /// </code>
316 ///
317 /// Outputs:
318 ///
319 /// <code lang="xml">
320 /// &lt;form method='post' action='/[appdir]/[controller]/Save.[extension]' id='productform'&gt;
321 /// </code>
323 /// </example>
324 ///
325 /// <remarks>
326 /// The parameters are used to build a url and also to form the tag. For notes on the url
327 /// see <see cref="DefaultUrlBuilder.BuildUrl(UrlInfo,IDictionary)"/>. The other parameters supported
328 /// follows
329 ///
330 /// <list type="table">
331 /// <term>
332 /// <term>noaction</term>
333 /// <description>boolean. Disables the generation of an action</description>
334 /// </term>
335 /// <term>
336 /// <term>method</term>
337 /// <description>string. The http method to use. Defaults to <c>post</c></description>
338 /// </term>
339 /// <term>
340 /// <term>id</term>
341 /// <description>string. The form id.</description>
342 /// </term>
343 /// </list>
344 ///
345 /// More parameters can be accepted depending on the form validation strategy you are using (if any).
346 ///
347 /// </remarks>
348 ///
349 /// <param name="parameters">The parameters for the tag or for action and form validation generation.</param>
350 /// <returns></returns>
351 public virtual string FormTag(IDictionary parameters)
353 string url = null;
355 // Creates action attribute
356 if (CommonUtils.ObtainEntryAndRemove(parameters, "noaction", "false") == "false")
358 url = UrlHelper.For(parameters);
361 return FormTag(url, parameters);
364 /// <summary>
365 /// Creates a form tag based on the parameters.
366 /// <para>
367 /// Javascript validation can also be bound to
368 /// the form and|or elements nested as long as the helper is
369 /// able to reach the <see cref="Type"/> of the object used on your view code
370 /// </para>
371 /// <para>
372 /// The action attribute generation will use <see cref="UrlHelper"/>
373 /// </para>
374 /// </summary>
375 ///
376 /// <example>
377 ///
378 /// <code lang="none">
379 /// $Form.FormTag('mytarget.castle', "%{id='productform'}")
380 /// </code>
381 ///
382 /// Outputs:
383 ///
384 /// <code lang="xml">
385 /// &lt;form method='post' action='mytarget.castle' id='productform'&gt;
386 /// </code>
388 /// </example>
389 ///
390 /// <remarks>
391 /// The following parameters are accepted.
392 ///
393 /// <list type="table">
394 /// <term>
395 /// <term>method</term>
396 /// <description>string. The http method to use. Defaults to <c>post</c></description>
397 /// </term>
398 /// <term>
399 /// <term>id</term>
400 /// <description>string. The form id.</description>
401 /// </term>
402 /// </list>
403 ///
404 /// More parameters can be accepted depending on the form validation strategy you are using (if any).
405 ///
406 /// </remarks>
407 ///
408 /// <param name="url">The hardcoded url.</param>
409 /// <param name="parameters">The parameters for the tag or for action and form validation generation.</param>
410 /// <returns></returns>
411 public virtual string FormTag(string url, IDictionary parameters)
413 string method = CommonUtils.ObtainEntryAndRemove(parameters, "method", "post");
414 currentFormId = CommonUtils.ObtainEntryAndRemove(parameters, "id", "form" + ++formCount);
416 validationConfig = ValidatorProvider.CreateConfiguration(parameters);
418 string afterFormTag = IsValidationEnabled ?
419 validationConfig.CreateAfterFormOpened(currentFormId) :
420 String.Empty;
422 string formContent;
424 if (url != null)
426 formContent = "<form action='" + url + "' method='" + method + "' " +
427 "id='" + currentFormId + "' " + GetAttributes(parameters) + ">";
429 else
431 formContent = "<form method='" + method + "' id='" + currentFormId + "' " + GetAttributes(parameters) + ">";
434 return formContent + afterFormTag;
437 /// <summary>
438 /// Generate Ajax form tag for ajax based form submission. Experimental.
439 /// </summary>
440 /// <param name="parameters"></param>
441 /// <returns></returns>
442 public virtual string AjaxFormTag(IDictionary parameters)
444 currentFormId = CommonUtils.ObtainEntryAndRemove(parameters, "id", "form" + ++formCount);
446 validationConfig = ValidatorProvider.CreateConfiguration(parameters);
448 string afterFormTag = IsValidationEnabled ?
449 validationConfig.CreateAfterFormOpened(currentFormId) :
450 String.Empty;
452 string url = UrlHelper.For(parameters);
454 parameters["form"] = true;
456 if (parameters.Contains("onsubmit"))
458 string onSubmitFunc = CommonUtils.ObtainEntryAndRemove(parameters, "onsubmit");
459 //remove return to make it compatible for ajax condition
460 if (onSubmitFunc.StartsWith("return ", StringComparison.InvariantCultureIgnoreCase))
462 onSubmitFunc = onSubmitFunc.Substring(7);
464 if (onSubmitFunc.EndsWith(";", StringComparison.InvariantCultureIgnoreCase))
466 onSubmitFunc = onSubmitFunc.Remove(onSubmitFunc.Length - 1);
468 string conditionFunc = CommonUtils.ObtainEntryAndRemove(parameters, "condition", string.Empty);
469 if (!string.IsNullOrEmpty(conditionFunc))
471 conditionFunc += " && ";
473 conditionFunc += onSubmitFunc;
475 parameters["condition"] = conditionFunc;
477 bool isMethodAssigned = parameters.Contains("method");
479 string method = CommonUtils.ObtainEntryAndRemove(parameters, "method", "post");
481 parameters["url"] = url;
483 // reassign method so in case if there is no value the default is assigned.
485 if (isMethodAssigned)
487 parameters["method"] = method;
490 String remoteFunc = new AjaxHelper().RemoteFunction(parameters);
492 string formContent = String.Format("<form id='{1}' method='{2}' {3} onsubmit=\"{0}; return false;\" enctype=\"multipart/form-data\">", remoteFunc, currentFormId, method, GetAttributes(parameters));
494 return formContent + afterFormTag;
497 /// <summary>
498 /// Renders an end form element.
499 /// </summary>
500 /// <remarks>
501 /// Should be used if you are using form validation. Some validation approaches
502 /// uses the end form before or after appending a javascript snippet.
503 /// </remarks>
504 /// <returns></returns>
505 public virtual string EndFormTag()
507 string beforeEndTag = string.Empty;
509 if (validationConfig != null)
511 beforeEndTag = IsValidationEnabled ?
512 validationConfig.CreateBeforeFormClosed(currentFormId) :
513 String.Empty;
516 return beforeEndTag + "</form>";
519 #endregion
521 #region Object scope related
523 /// <summary>
524 /// Pushes the specified target. Experimental.
525 /// </summary>
526 /// <param name="target">The target.</param>
527 public virtual void Push(string target)
529 Push(target, null);
532 /// <summary>
533 /// Pushes the specified target. Experimental.
534 /// </summary>
535 /// <param name="target">The target.</param>
536 /// <param name="parameters">The parameters.</param>
537 public virtual void Push(string target, IDictionary parameters)
539 string disableValidation = CommonUtils.ObtainEntryAndRemove(parameters, "disablevalidation", "false");
540 object value = ObtainValue(target);
542 if (value != null)
544 objectStack.Push(new FormScopeInfo(target, disableValidation != "true"));
546 else
548 value = ObtainValue(target + "type");
550 if (value != null)
552 objectStack.Push(new FormScopeInfo(target, disableValidation != "true"));
554 else
556 throw new ArgumentException("target could not be evaluated during Push operation. Target: " + target);
561 /// <summary>
562 /// Pops this instance. Experimental.
563 /// </summary>
564 public virtual void Pop()
566 objectStack.Pop();
569 #endregion
571 #region Submit and Button related
573 /// <summary>
574 /// Generates an input submit element.
575 /// </summary>
576 /// <param name="value">The value/caption for the button.</param>
577 /// <returns>The element tag</returns>
578 public virtual string Submit(string value)
580 return Submit(value, null);
583 /// <summary>
584 /// Generates an input submit element.
585 /// </summary>
586 /// <param name="value">The value/caption for the button.</param>
587 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
588 /// <returns>The element tag</returns>
589 public virtual string Submit(string value, IDictionary attributes)
591 return CreateInputElement("submit", value, attributes);
594 /// <summary>
595 /// Generates an graphical submit element.
596 /// </summary>
597 /// <param name="imgsrc">The path the image file.</param>
598 /// <param name="alttext">The alt text displayed by screenreaders, or when images are not enabled.</param>
599 /// <returns>The element tag</returns>
600 public virtual string ImageSubmit(string imgsrc, string alttext)
602 return ImageSubmit(imgsrc, alttext, null);
605 /// <summary>
606 /// Generates an input submit element.
607 /// </summary>
608 /// <param name="imgsrc">The path the image file.</param>
609 /// <param name="alttext">The alt text displayed by screenreaders, or when images are not enabled.</param>
610 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
611 /// <returns>The element tag</returns>
612 public virtual string ImageSubmit(string imgsrc, string alttext, IDictionary attributes)
614 attributes = attributes != null ? attributes : new Hashtable();
615 attributes["src"] = imgsrc;
616 attributes["alt"] = alttext;
617 return CreateInputElement("image", alttext, attributes);
620 /// <summary>
621 /// Generates an input button element.
622 /// </summary>
623 /// <param name="value">The value.</param>
624 /// <returns>The element tag</returns>
625 public virtual string Button(string value)
627 return Button(value, null);
630 /// <summary>
631 /// Generates an input button element.
632 /// </summary>
633 /// <param name="value">The value.</param>
634 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
635 /// <returns>The element tag</returns>
636 public virtual string Button(string value, IDictionary attributes)
638 return CreateInputElement("button", value, attributes);
641 /// <summary>
642 /// Creates a basic button element of type submit.
643 /// </summary>
644 /// <param name="innerText">The inner text of the button element.</param>
645 /// <returns>The generated button element.</returns>
646 public virtual string ButtonElement(string innerText)
648 return ButtonElement(innerText, "submit", null);
651 /// <summary>
652 /// Creates a basic button element of the specified type.
653 /// </summary>
654 /// <param name="innerText">The inner text of the button element.</param>
655 /// <param name="type">The type of the button.</param>
656 /// <returns>The generated button element.</returns>
657 public virtual string ButtonElement(string innerText, string type)
659 return ButtonElement(innerText, type, null);
662 /// <summary>
663 /// Creates a basic button element of the specified type and with specified attributes.
664 /// </summary>
665 /// <param name="innerText">The inner text of the button element.</param>
666 /// <param name="type">The type of the button.</param>
667 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
668 /// <returns>The generated button element.</returns>
669 public virtual string ButtonElement(string innerText, string type, IDictionary attributes)
671 return String.Format("<button type=\"{0}\" {1}>{2}</button>", type, GetAttributes(attributes), innerText);
674 #endregion
676 #region TextFieldValue
678 /// <summary>
679 /// Generates an input text form element
680 /// with the supplied value
681 /// </summary>
682 /// <param name="target">The string to be used to create the element name.</param>
683 /// <param name="value">Value to supply to the element (instead of querying the target)</param>
684 /// <returns>The generated form element</returns>
685 public string TextFieldValue(string target, object value)
687 return TextFieldValue(target, value, null);
690 /// <summary>
691 /// Generates an input text form element
692 /// with the supplied value
693 /// </summary>
694 /// <param name="target">The string to be used to create the element name.</param>
695 /// <param name="value">Value to supply to the element (instead of querying the target)</param>
696 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
697 /// <returns>The generated form element</returns>
698 public string TextFieldValue(string target, object value, IDictionary attributes)
700 return CreateInputElement("text", target, value, attributes);
703 #endregion
705 #region TextField
707 /// <summary>
708 /// Generates an input text element.
709 /// <para>
710 /// The value is extracted from the target (if available)
711 /// </para>
712 /// </summary>
713 ///
714 /// <example>
715 /// The following example assumes that an entry <c>username</c> exists on the
716 /// <see cref="Controller.PropertyBag"/> or <see cref="Controller.Flash"/> or <see cref="Controller.Session"/>
717 ///
718 /// <code lang="none">
719 /// $Form.TextField('username')
720 /// </code>
721 /// Outputs:
722 /// <code lang="xml">
723 /// &lt;input type='text' name='username' id='username' value='John Doe' /&gt;
724 /// </code>
725 ///
726 /// <para>
727 /// The following example assumes that an entry <c>user</c> exists on the
728 /// <see cref="Controller.PropertyBag"/> or <see cref="Controller.Flash"/> or <see cref="Controller.Session"/>
729 /// </para>
730 ///
731 /// <code lang="none">
732 /// $Form.TextField('user.name')
733 /// </code>
734 /// Outputs:
735 /// <code lang="xml">
736 /// &lt;input type='text' name='user.name' id='user_name' value='John Doe' /&gt;
737 /// </code>
738 /// </example>
739 ///
740 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
741 /// <returns>The generated form element</returns>
742 public virtual string TextField(string target)
744 return TextField(target, null);
747 /// <summary>
748 /// Generates an input text element.
749 /// <para>
750 /// The value is extracted from the target (if available)
751 /// </para>
752 /// </summary>
753 ///
754 /// <seealso cref="TextField(string)"/>
755 ///
756 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
757 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
758 /// <returns>The generated form element</returns>
759 public virtual string TextField(string target, IDictionary attributes)
761 target = RewriteTargetIfWithinObjectScope(target);
763 object value = ObtainValue(target);
765 ApplyValidation(InputElementType.Text, target, ref attributes);
767 return CreateInputElement("text", target, value, attributes);
770 /// <summary>
771 /// Combines <see cref="AjaxHelper.InputTextWithAutoCompletion(string,string,IDictionary,IDictionary)"/>
772 /// with <see cref="TextField(string,IDictionary)"/> to achieve an TextField that offers
773 /// both input completion and databinding support.
774 /// </summary>
775 /// <param name="target">The target of the text field (analogous to <see cref="TextField(string,IDictionary)"/>)</param>
776 /// <param name="url">The url to call for completion options (analogous to <see cref="AjaxHelper.InputTextWithAutoCompletion(string,string,IDictionary,IDictionary)"/>)</param>
777 /// <param name="tagAttributes">The attributes to apply to the text input field. If this dictionary does not contain a value for browser-based autocompletion (autocomplete="off|on"), it will default to "off" to prevent interference of AJAX-based and browser-based autocompletion.</param>
778 /// <param name="completionOptions">The options for the AJAX-call analogous to <see cref="AjaxHelper.InputTextWithAutoCompletion(string,string,IDictionary,IDictionary)"/>.</param>
779 /// <returns>The generated form elements.</returns>
780 /// <remarks>Please note that this function requires Ajax scripts (Prototype/Scriptaculous)</remarks>
781 public virtual string TextFieldAutoComplete(string target, string url, IDictionary tagAttributes, IDictionary completionOptions)
783 if (!tagAttributes.Contains("autocomplete")) tagAttributes.Add("autocomplete", "off");
785 StringBuilder sb = new StringBuilder();
786 sb.Append(TextField(target, tagAttributes));
788 string textFieldId = CreateHtmlId(tagAttributes, target);
789 sb.AppendFormat("<div id=\"{0}\" class=\"auto_complete\"></div>", textFieldId + "autocomplete");
790 sb.Append(new AjaxHelper().AutoCompleteInputText(textFieldId, url, completionOptions));
792 return sb.ToString();
796 #endregion
798 #region FilteredTextField
800 /// <summary>
801 /// Generates an input text element with a javascript that prevents the
802 /// chars listed in the forbid attribute from being entered.
803 /// </summary>
804 /// <para>
805 /// You must pass an <c>forbid</c> value through the dictionary.
806 /// It must be a comma separated list of chars that cannot be accepted on the field.
807 /// For example:
808 /// </para>
809 /// <code>
810 /// FormHelper.FilteredTextField("product.price", {forbid='46'})
811 /// </code>
812 /// In this case the key code 46 (period) will not be accepted on the field.
813 /// <para>
814 /// The value is extracted from the target (if available).
815 /// </para>
816 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
817 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
818 /// <returns>The generated form element.</returns>
819 /// <remarks>
820 /// You must invoke <see cref="FormHelper.InstallScripts"/> before using it.
821 /// </remarks>
822 public virtual string FilteredTextField(string target, IDictionary attributes)
824 target = RewriteTargetIfWithinObjectScope(target);
826 object value = ObtainValue(target);
828 attributes = attributes != null ? attributes : new Hashtable();
830 ApplyFilterOptions(attributes);
831 ApplyValidation(InputElementType.Text, target, ref attributes);
833 return CreateInputElement("text", target, value, attributes);
836 #endregion
838 #region NumberField
840 /// <summary>
841 /// Generates an input text element with a javascript that prevents
842 /// chars other than numbers from being entered.
843 /// <para>
844 /// The value is extracted from the target (if available)
845 /// </para>
846 /// </summary>
847 ///
848 /// <seealso cref="InstallScripts"/>
849 /// <seealso cref="NumberField(string,IDictionary)"/>
850 ///
851 /// <remarks>
852 /// You must include the formhelper javascript functions to use the NumberField.
853 /// See <see cref="InstallScripts"/>
854 /// </remarks>
855 ///
856 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
857 /// <returns>The generated form element</returns>
858 public virtual string NumberField(string target)
860 return NumberField(target, null);
863 /// <summary>
864 /// Generates an input text element with a javascript that prevents
865 /// chars other than numbers from being entered.
866 /// <para>
867 /// The value is extracted from the target (if available)
868 /// </para>
869 /// </summary>
870 ///
871 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
872 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
873 /// <returns>The generated form element</returns>
874 ///
875 /// <remarks>
876 /// You must include the formhelper javascript functions to use the NumberField.
877 /// See <see cref="InstallScripts"/>
878 /// <para>
879 /// You can optionally pass an <c>exceptions</c> value through the dictionary.
880 /// It must be a comma separated list of chars that can be accepted on the field.
881 /// For example:
882 /// </para>
883 /// <code>
884 /// FormHelper.NumberField("product.price", {exceptions='13,10,11'})
885 /// </code>
886 /// In this case the key codes 13, 10 and 11 will be accepted on the field.
887 /// <para>
888 /// You can aslo optionally pass an <c>forbid</c> value through the dictionary.
889 /// It must be a comma separated list of chars that cannot be accepted on the field.
890 /// For example:
891 /// </para>
892 /// <code>
893 /// FormHelper.NumberField("product.price", {forbid='46'})
894 /// </code>
895 /// In this case the key code 46 (period) will not be accepted on the field.
896 /// </remarks>
897 public virtual string NumberField(string target, IDictionary attributes)
899 target = RewriteTargetIfWithinObjectScope(target);
901 object value = ObtainValue(target);
903 attributes = attributes != null ? attributes : new Hashtable();
905 ApplyNumberOnlyOptions(attributes);
906 ApplyValidation(InputElementType.Text, target, ref attributes);
908 return CreateInputElement("text", target, value, attributes);
911 #endregion
913 #region NumberFieldValue
915 /// <summary>
916 /// Generates an input text element with a javascript that prevents
917 /// chars other than numbers from being entered. The value is not gathered
918 /// from the context, instead you specify it on the second argument
919 /// </summary>
920 ///
921 /// <seealso cref="InstallScripts"/>
922 /// <seealso cref="NumberField(string,IDictionary)"/>
923 ///
924 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
925 /// <param name="value">The current value to output.</param>
926 /// <returns>The generated form element</returns>
927 ///
928 /// <remarks>
929 /// You must include the formhelper javascript functions to use the NumberField.
930 /// See <see cref="InstallScripts"/>
931 /// </remarks>
932 public virtual string NumberFieldValue(string target, object value)
934 return NumberFieldValue(target, value, null);
937 /// <summary>
938 /// Generates an input text element with a javascript that prevents
939 /// chars other than numbers from being entered. The value is not gathered
940 /// from the context, instead you specify it on the second argument
941 /// </summary>
942 ///
943 /// <seealso cref="InstallScripts"/>
944 /// <seealso cref="NumberField(string,IDictionary)"/>
945 ///
946 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
947 /// <param name="value">The current value to output.</param>
948 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
949 /// <returns>The generated form element</returns>
950 ///
951 /// <remarks>
952 /// You must include the formhelper javascript functions to use the NumberField.
953 /// See <see cref="InstallScripts"/>
954 /// </remarks>
955 public virtual string NumberFieldValue(string target, object value, IDictionary attributes)
957 target = RewriteTargetIfWithinObjectScope(target);
959 attributes = attributes ?? new Hashtable();
961 ApplyNumberOnlyOptions(attributes);
962 ApplyValidation(InputElementType.Text, target, ref attributes);
964 return CreateInputElement("text", target, value, attributes);
967 #endregion
969 #region TextArea
971 /// <summary>
972 /// Generates a textarea element.
973 /// <para>
974 /// The value is extracted from the target (if available)
975 /// </para>
976 /// </summary>
977 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
978 /// <returns>The generated form element</returns>
979 public virtual string TextArea(string target)
981 return TextArea(target, null);
984 /// <summary>
985 /// Generates a textarea element.
986 /// <para>
987 /// The value is extracted from the target (if available)
988 /// </para>
989 /// </summary>
990 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
991 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
992 /// <returns>The generated form element</returns>
993 public virtual string TextArea(string target, IDictionary attributes)
995 string targetForValue = RewriteTargetIfWithinObjectScope(target);
996 object value = ObtainValue(targetForValue);
997 return TextAreaValue(target, value, attributes);
1000 /// <summary>
1001 /// Generates a textarea element with a specified value.
1002 /// </summary>
1003 /// <param name="target">The target to base the element name on.</param>
1004 /// <param name="value">The value to apply to the field.</param>
1005 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1006 /// <returns>The generated form element</returns>
1007 public virtual string TextAreaValue(string target, object value, IDictionary attributes)
1009 target = RewriteTargetIfWithinObjectScope(target);
1011 value = value == null ? "" : HtmlEncode(value.ToString());
1013 string id = CreateHtmlId(target);
1015 ApplyValidation(InputElementType.Text, target, ref attributes);
1017 return String.Format("<textarea id=\"{0}\" name=\"{1}\" {2}>{3}</textarea>",
1018 id, target, GetAttributes(attributes), FormatIfNecessary(value, attributes));
1021 #endregion
1023 #region PasswordField
1025 /// <summary>
1026 /// Generates a password input field.
1027 /// </summary>
1028 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1029 /// <returns>The generated form element</returns>
1030 public virtual string PasswordField(string target)
1032 return PasswordField(target, null);
1035 /// <summary>
1036 /// Generates a password input field.
1037 /// </summary>
1038 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1039 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1040 /// <returns>The generated form element</returns>
1041 public virtual string PasswordField(string target, IDictionary attributes)
1043 target = RewriteTargetIfWithinObjectScope(target);
1045 object value = ObtainValue(target);
1047 ApplyValidation(InputElementType.Text, target, ref attributes);
1049 return CreateInputElement("password", target, value, attributes);
1052 #endregion
1054 #region PasswordNumberField
1056 /// <summary>
1057 /// Generates an input password element with a javascript that prevents
1058 /// chars other than numbers from being entered.
1059 /// <para>
1060 /// The value is extracted from the target (if available)
1061 /// </para>
1062 /// </summary>
1063 /// <remarks>
1064 /// You must invoke <see cref="FormHelper.InstallScripts"/> before using it
1065 /// </remarks>
1066 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1067 /// <returns>The generated form element</returns>
1068 public virtual string PasswordNumberField(string target)
1070 return PasswordNumberField(target, null);
1073 /// <summary>
1074 /// Generates an input password element with a javascript that prevents
1075 /// chars other than numbers from being entered.
1076 /// <para>
1077 /// The value is extracted from the target (if available)
1078 /// </para>
1079 /// <para>
1080 /// You can optionally pass an <c>exceptions</c> value through the dictionary.
1081 /// It must be a comma separated list of chars that can be accepted on the field.
1082 /// For example:
1083 /// </para>
1084 /// <code>
1085 /// FormHelper.NumberField("product.price", {exceptions='13,10,11'})
1086 /// </code>
1087 /// In this case the key codes 13, 10 and 11 will be accepted on the field.
1088 /// <para>
1089 /// You can aslo optionally pass an <c>forbid</c> value through the dictionary.
1090 /// It must be a comma separated list of chars that cannot be accepted on the field.
1091 /// For example:
1092 /// </para>
1093 /// <code>
1094 /// FormHelper.NumberField("product.price", {forbid='46'})
1095 /// </code>
1096 /// In this case the key code 46 (period) will not be accepted on the field.
1097 /// </summary>
1098 /// <remarks>
1099 /// You must invoke <see cref="FormHelper.InstallScripts"/> before using it
1100 /// </remarks>
1101 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1102 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1103 /// <returns>The generated form element</returns>
1104 public virtual string PasswordNumberField(string target, IDictionary attributes)
1106 target = RewriteTargetIfWithinObjectScope(target);
1108 object value = ObtainValue(target);
1110 attributes = attributes != null ? attributes : new Hashtable();
1112 ApplyNumberOnlyOptions(attributes);
1113 ApplyValidation(InputElementType.Text, target, ref attributes);
1115 return CreateInputElement("password", target, value, attributes);
1118 #endregion
1120 #region LiteralFor
1122 ///<summary>Returns the value for specified target with no additional markup. If no value is obtained
1123 /// an empty string is returned.
1124 ///</summary>
1125 ///<param name="target">The object to get the value from.</param>
1126 ///<returns>The value or an empty string if none is found.</returns>
1127 public virtual string LiteralFor(string target)
1129 target = RewriteTargetIfWithinObjectScope(target);
1130 object value = ObtainValue(target);
1131 if (value == null)
1133 return string.Empty;
1135 return value.ToString();
1138 #endregion
1140 #region LabelFor
1142 /// <summary>
1143 /// Generates a label element.
1144 /// </summary>
1145 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1146 /// <param name="label">Legend</param>
1147 /// <returns>The generated form element</returns>
1148 public virtual string LabelFor(string target, string label)
1150 return LabelFor(target, label, null);
1153 /// <summary>
1154 /// Generates a label element.
1155 /// </summary>
1156 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1157 /// <param name="label">Legend</param>
1158 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1159 /// <returns>The generated form element</returns>
1160 public virtual string LabelFor(string target, string label, IDictionary attributes)
1162 target = RewriteTargetIfWithinObjectScope(target);
1164 string id = CreateHtmlId(attributes, target);
1166 StringBuilder sb = new StringBuilder();
1167 StringWriter sbWriter = new StringWriter(sb);
1168 HtmlTextWriter writer = new HtmlTextWriter(sbWriter);
1170 writer.WriteBeginTag("label");
1171 writer.WriteAttribute("for", id);
1172 string strAttributes = GetAttributes(attributes);
1173 if (strAttributes != String.Empty)
1175 writer.Write(HtmlTextWriter.SpaceChar);
1178 writer.Write(strAttributes);
1179 writer.Write(HtmlTextWriter.TagRightChar);
1180 writer.Write(label);
1181 writer.WriteEndTag("label");
1183 return sbWriter.ToString();
1186 #endregion
1188 #region HiddenField
1190 /// <summary>
1191 /// Generates a hidden form element.
1192 /// <para>
1193 /// The value is extracted from the target (if available)
1194 /// </para>
1195 /// </summary>
1196 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1197 /// <returns>The generated form element</returns>
1198 public virtual string HiddenField(string target)
1200 target = RewriteTargetIfWithinObjectScope(target);
1202 object value = ObtainValue(target);
1204 return CreateInputElement("hidden", target, value, null);
1207 /// <summary>
1208 /// Generates a hidden form element with the specified value
1209 /// </summary>
1210 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1211 /// <param name="value">The value for the hidden field</param>
1212 /// <returns>The generated form element</returns>
1213 public virtual string HiddenField(string target, object value)
1215 return CreateInputElement("hidden", target, value, null);
1218 /// <summary>
1219 /// Generates a hidden form element.
1220 /// <para>
1221 /// The value is extracted from the target (if available)
1222 /// </para>
1223 /// </summary>
1224 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1225 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1226 /// <returns>The generated form element</returns>
1227 public virtual string HiddenField(string target, IDictionary attributes)
1229 target = RewriteTargetIfWithinObjectScope(target);
1231 object value = ObtainValue(target);
1233 string id = CreateHtmlId(attributes, target);
1235 value = value != null ? value : String.Empty;
1237 return CreateInputElement("hidden", id, target, value.ToString(), attributes);
1240 /// <summary>
1241 /// Generates a hidden form element with the specified value
1242 /// </summary>
1243 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1244 /// <param name="value">The value for the hidden field</param>
1245 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1246 /// <returns>The generated form element</returns>
1247 public virtual string HiddenField(string target, object value, IDictionary attributes)
1249 return CreateInputElement("hidden", target, value, attributes);
1252 #endregion
1254 #region CheckboxList
1256 /// <summary>
1257 /// Creates a <see cref="CheckboxList"/> instance
1258 /// which is enumerable. For each interaction you can invoke
1259 /// <see cref="CheckboxList.Item()"/> which will correctly render
1260 /// a checkbox input element for the current element on the supplied set (<c>dataSource</c>).
1261 /// <para>
1262 /// The enumerable item will be an element of the <c>dataSource</c>.
1263 /// </para>
1264 /// If the <c>dataSource</c>
1265 /// elements are complex objects (ie not string or primitives),
1266 /// supply the parameters <c>value</c> and <c>text</c> to the dictionary to make
1267 /// the helper use the specified properties to extract the <c>option</c> value and content respectively.
1268 /// <para>
1269 /// Usually both the <c>target</c> and obviously the <c>dataSource</c> are sets
1270 /// with multiple items. The element types tend to be the same. If
1271 /// they are not, you might have to specify the <c>suffix</c> parameters on
1272 /// the <c>attributes</c> as it would not be inferred.
1273 /// </para>
1274 /// </summary>
1275 ///
1276 /// <example>
1277 /// Consider the following action code:
1278 /// <code>
1279 /// public void Index()
1280 /// {
1281 /// // data source
1282 /// PropertyBag["primenumbers"] = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
1283 ///
1284 /// // initial selection
1285 /// PropertyBag["selectedPrimes"] = new int[] { 11, 19 };
1286 /// }
1287 /// </code>
1288 ///
1289 /// And the respective view code
1290 ///
1291 /// <code lang="none">
1292 /// #set($items = $FormHelper.CreateCheckboxList("selectedPrimes", $primenumbers))
1293 ///
1294 /// #foreach($elem in $items)
1295 /// $items.Item() $elem
1296 /// #end
1297 /// </code>
1298 ///
1299 /// That will generates the following html:
1300 ///
1301 /// <code lang="none">
1302 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_0_&quot; name=&quot;selectedPrimes[0]&quot; value=&quot;2&quot; /&gt; 2
1303 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_1_&quot; name=&quot;selectedPrimes[1]&quot; value=&quot;3&quot; /&gt; 3
1304 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_2_&quot; name=&quot;selectedPrimes[2]&quot; value=&quot;5&quot; /&gt; 5
1305 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_3_&quot; name=&quot;selectedPrimes[3]&quot; value=&quot;7&quot; /&gt; 7
1306 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_4_&quot; name=&quot;selectedPrimes[4]&quot; value=&quot;11&quot; checked=&quot;checked&quot; /&gt; 11
1307 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_5_&quot; name=&quot;selectedPrimes[5]&quot; value=&quot;13&quot; /&gt; 13
1308 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_6_&quot; name=&quot;selectedPrimes[6]&quot; value=&quot;17&quot; /&gt; 17
1309 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_7_&quot; name=&quot;selectedPrimes[7]&quot; value=&quot;19&quot; checked=&quot;checked&quot; /&gt; 19
1310 /// &lt;input type=&quot;checkbox&quot; id=&quot;selectedPrimes_8_&quot; name=&quot;selectedPrimes[8]&quot; value=&quot;23&quot; /&gt; 23
1311 /// </code>
1312 ///
1313 /// <para>
1314 /// To customize the id, you can call the <see cref="CheckboxList.Item(string)"/> overload:
1315 /// </para>
1316 ///
1317 /// <code lang="none">
1318 /// #set($items = $FormHelper.CreateCheckboxList("selectedPrimes", $primenumbers))
1319 ///
1320 /// #foreach($elem in $items)
1321 /// $items.Item("myId${velocityCount}") $Form.LabelFor("myId${velocityCount}", $elem.ToString()) <br/>
1322 /// #end
1323 /// </code>
1324 /// </example>
1325 ///
1326 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1327 /// <param name="dataSource">The set of available elements</param>
1328 /// <returns>The generated form element</returns>
1329 public virtual CheckboxList CreateCheckboxList(string target, IEnumerable dataSource)
1331 return CreateCheckboxList(target, dataSource, null);
1334 /// <summary>
1335 /// Creates a <see cref="CheckboxList"/> instance
1336 /// which is enumerable. For each interaction you can invoke
1337 /// <see cref="CheckboxList.Item()"/> which will correctly render
1338 /// a checkbox input element for the current element on the supplied set (<c>dataSource</c>).
1339 /// <para>
1340 /// The enumerable item will be an element of the <c>dataSource</c>.
1341 /// </para>
1342 /// If the <c>dataSource</c>
1343 /// elements are complex objects (ie not string or primitives),
1344 /// supply the parameters <c>value</c> and <c>text</c> to the dictionary to make
1345 /// the helper use the specified properties to extract the <c>option</c> value and content respectively.
1346 /// <para>
1347 /// Usually both the <c>target</c> and obviously the <c>dataSource</c> are sets
1348 /// with multiple items. The element types tend to be the same. If
1349 /// they are not, you might have to specify the <c>suffix</c> parameters on
1350 /// the <c>attributes</c> as it would not be inferred.
1351 /// </para>
1352 /// </summary>
1353 ///
1354 /// <seealso cref="CreateCheckboxList(string,IEnumerable)"/>
1356 /// <example>
1357 /// Consider the following action code:
1358 /// <code>
1359 /// public void Index()
1360 /// {
1361 /// Category[] categories = new Category[] { new Category(1, "Music"), new Category(2, "Humor"), new Category(3, "Politics") };
1362 /// PropertyBag["categories"] = categories; // datasource
1363 ///
1364 /// Blog blog = new Blog();
1365 /// blog.Categories = new Category[] { new Category(2, "Humor") }; // initial selection
1366 /// PropertyBag["blog"] = blog;
1367 /// }
1368 /// </code>
1369 ///
1370 /// And the respective view code
1371 ///
1372 /// <code lang="none">
1373 /// #set($items = $Form.CreateCheckboxList("blog.categories", $categories, "%{value='Id'}"))
1374 ///
1375 /// #foreach($elem in $items)
1376 /// $items.Item() $elem
1377 /// #end
1378 /// </code>
1379 ///
1380 /// That will generates the following html:
1381 ///
1382 /// <code lang="none">
1383 /// &lt;input type=&quot;checkbox&quot; id=&quot;blog_categories_0_&quot; name=&quot;blog.categories[0].Id&quot; value=&quot;1&quot; /&gt; Music
1384 /// &lt;input type=&quot;checkbox&quot; id=&quot;blog_categories_1_&quot; name=&quot;blog.categories[1].Id&quot; value=&quot;2&quot; checked=&quot;checked&quot; /&gt; Humor
1385 /// &lt;input type=&quot;checkbox&quot; id=&quot;blog_categories_2_&quot; name=&quot;blog.categories[2].Id&quot; value=&quot;3&quot; /&gt; Politics
1386 /// </code>
1387 ///
1388 /// </example>
1389 ///
1390 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1391 /// <param name="dataSource">The set of available elements</param>
1392 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1393 /// <returns>The generated form element</returns>
1394 public virtual CheckboxList CreateCheckboxList(string target, IEnumerable dataSource, IDictionary attributes)
1396 target = RewriteTargetIfWithinObjectScope(target);
1398 object value = ObtainValue(target);
1400 return new CheckboxList(this, target, value, dataSource, attributes);
1403 /// <summary>
1404 /// Outputs a checkbox element (for internal use)
1405 /// </summary>
1406 /// <param name="index"></param>
1407 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1408 /// <param name="suffix"></param>
1409 /// <param name="item"></param>
1410 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1411 /// <returns>The generated form element</returns>
1412 internal string CheckboxItem(int index, string target, string suffix, SetItem item, IDictionary attributes)
1414 if (item.IsSelected)
1416 AddChecked(attributes);
1418 else
1420 RemoveChecked(attributes);
1423 target = String.Format("{0}[{1}]", target, index);
1425 string elementId = CreateHtmlId(attributes, target, true);
1427 string computedTarget = target;
1429 if (suffix != null && suffix != String.Empty)
1431 computedTarget += "." + suffix;
1434 return CreateInputElement("checkbox", elementId, computedTarget, item.Value, attributes);
1437 /// <summary>
1438 /// Creates a label for an item of the checkbox list (internal use). The method mirrors
1439 /// <see cref="CheckboxItem"/> to ensure that the HTML ID is created consistently.
1440 /// </summary>
1441 /// <param name="index">Index for creating HTML ID</param>
1442 /// <param name="target">Target object for which the HTML ID is needed</param>
1443 /// <param name="suffix"></param>
1444 /// <param name="label">The label to display</param>
1445 /// <param name="attributes">additional attributes that influence HTML ID creation</param>
1446 /// <returns></returns>
1447 internal string CheckboxLabel(int index, string target, string suffix, string label, IDictionary attributes)
1449 target = String.Format("{0}[{1}]", target, index);
1451 string elementId = CreateHtmlId(attributes, target, true);
1453 return "<label for=\"" + elementId + "\" " + GetAttributes(attributes) + ">" + label + "</label>";
1456 /// <summary>
1457 /// This class is an enumerable list of checkboxes.
1458 /// It uses the <see cref="OperationState"/> to manage the sets
1459 /// and to control the check/uncheck state.
1460 /// </summary>
1461 public sealed class CheckboxList : IEnumerable, IEnumerator
1463 private readonly FormHelper helper;
1464 private readonly string target;
1465 private readonly IDictionary attributes;
1466 private readonly OperationState operationState;
1467 private readonly IEnumerator enumerator;
1468 private bool hasMovedNext, hasItem;
1469 private int index = -1;
1471 /// <summary>
1472 /// Initializes a new instance of the <see cref="CheckboxList"/> class.
1473 /// </summary>
1474 /// <param name="helper">The helper.</param>
1475 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1476 /// <param name="initialSelectionSet">The initial selection set.</param>
1477 /// <param name="dataSource">The set of available elements</param>
1478 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1479 public CheckboxList(FormHelper helper, string target,
1480 object initialSelectionSet, IEnumerable dataSource, IDictionary attributes)
1482 if (dataSource == null) throw new ArgumentNullException("dataSource");
1484 this.helper = helper;
1485 this.target = target;
1486 this.attributes = attributes ?? new HybridDictionary(true);
1488 operationState = SetOperation.IterateOnDataSource(initialSelectionSet, dataSource, attributes);
1489 enumerator = operationState.GetEnumerator();
1492 /// <summary>
1493 /// Outputs the Checkbox in the correct state (checked/unchecked) based
1494 /// on the Set.
1495 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1496 /// </summary>
1497 /// <returns>The generated input element</returns>
1498 public string Item()
1500 return Item(null);
1503 /// <summary>
1504 /// Outputs the Checkbox in the correct state (checked/unchecked) based
1505 /// on the Set.
1506 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1507 /// </summary>
1508 /// <param name="id">The element id</param>
1509 /// <returns>The generated input element</returns>
1510 public string Item(string id)
1512 if (!hasMovedNext)
1514 throw new InvalidOperationException("Before rendering a checkbox item, you must use MoveNext");
1517 if (!hasItem)
1519 // Nothing to render
1520 return String.Empty;
1523 if (id != null)
1525 attributes["id"] = id;
1528 return helper.CheckboxItem(index, target, operationState.TargetSuffix, CurrentSetItem, attributes);
1531 /// <summary>
1532 /// Outputs a label for the current checkbox element based on the generated id.
1533 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1534 /// </summary>
1535 /// <param name="label">The text to display</param>
1536 /// <returns>The generated label element</returns>
1537 public string LabelFor(string label)
1539 return LabelFor(null, label, null);
1542 /// <summary>
1543 /// Outputs a label for the current checkbox element based on the generated id.
1544 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1545 /// </summary>
1546 /// <param name="label">The text to display</param>
1547 /// <param name="attributes">The attributes.</param>
1548 /// <returns>The generated label element</returns>
1549 public string LabelFor(string label, IDictionary attributes)
1551 return LabelFor(null, label, attributes);
1554 /// <summary>
1555 /// Outputs a label for the current checkbox element based on the given id.
1556 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1557 /// </summary>
1558 /// <param name="id">The id to use within the label</param>
1559 /// <param name="label">The text to display</param>
1560 /// <param name="attributes">The attributes.</param>
1561 /// <returns>The generated label element</returns>
1562 public string LabelFor(string id, string label, IDictionary attributes)
1564 if (!hasMovedNext)
1566 throw new InvalidOperationException("Before rendering a checkbox item, you must use MoveNext");
1569 if (attributes == null)
1571 attributes = new HybridDictionary(true);
1574 if (!hasItem)
1576 // Nothing to render
1577 return String.Empty;
1580 if (id != null)
1582 attributes["id"] = id;
1585 return helper.CheckboxLabel(index, target, operationState.TargetSuffix, label, attributes);
1588 /// <summary>
1589 /// Returns an enumerator that iterates through a collection.
1590 /// </summary>
1591 /// <returns>
1592 /// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
1593 /// </returns>
1594 public IEnumerator GetEnumerator()
1596 return this;
1599 /// <summary>
1600 /// Advances the enumerator to the next element of the collection.
1601 /// </summary>
1602 /// <returns>
1603 /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
1604 /// </returns>
1605 /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
1606 public bool MoveNext()
1608 hasMovedNext = true;
1609 hasItem = enumerator.MoveNext();
1611 if (hasItem) index++;
1613 return hasItem;
1616 /// <summary>
1617 /// Sets the enumerator to its initial position, which is before the first element in the collection.
1618 /// </summary>
1619 /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
1620 public void Reset()
1622 index = -1;
1623 enumerator.Reset();
1626 /// <summary>
1627 /// Gets the current element in the collection.
1628 /// </summary>
1629 /// <value></value>
1630 /// <returns>The current element in the collection.</returns>
1631 /// <exception cref="T:System.InvalidOperationException">The enumerator is positioned before the first element of the collection or after the last element. </exception>
1632 public object Current
1634 get { return CurrentSetItem.Item; }
1637 /// <summary>
1638 /// Gets the current set item.
1639 /// </summary>
1640 /// <value>The current set item.</value>
1641 public SetItem CurrentSetItem
1643 get { return enumerator.Current as SetItem; }
1647 #endregion
1649 #region CheckboxField
1651 /// <summary>
1652 /// Generates a checkbox field. In fact it generates two as a
1653 /// way to send a value if the primary checkbox is not checked.
1654 /// This allow the process the be aware of the unchecked value
1655 /// and act accordingly.
1656 /// </summary>
1657 ///
1658 /// <example>
1659 /// Consider the following view code:
1660 ///
1661 /// <code lang="none">
1662 /// $Form.CheckboxField('user.disabled')
1663 /// </code>
1664 ///
1665 /// That is going to output:
1666 ///
1667 /// <code lang="none">
1668 /// &lt;input type=&quot;checkbox&quot; id=&quot;user_disabled&quot; name=&quot;user.disabled&quot; value=&quot;true&quot; /&gt;
1669 /// &lt;input type=&quot;hidden&quot; id=&quot;user_disabledH&quot; name=&quot;user.disabled&quot; value=&quot;false&quot; /&gt;
1670 /// </code>
1671 ///
1672 /// </example>
1673 ///
1674 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1675 /// <returns>The generated form element</returns>
1676 public virtual string CheckboxField(string target)
1678 return CheckboxField(target, null);
1681 /// <summary>
1682 /// Generates a checkbox field. In fact it generates two as a
1683 /// way to send a value if the primary checkbox is not checked.
1684 /// This allow the process the be aware of the unchecked value
1685 /// and act accordingly.
1686 ///
1687 /// <para>
1688 /// The checked and unchecked values sent to the server defaults
1689 /// to true and false. You can override them using the
1690 /// parameters <c>trueValue</c> and <c>falseValue</c>, but the DataBinder is prepared only
1691 /// to treat boolean arrays.
1692 /// </para>
1693 ///
1694 /// </summary>
1695 ///
1696 /// <seealso cref="CheckboxField(string)"/>
1697 ///
1698 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1699 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1700 /// <returns>The generated form element</returns>
1701 public virtual string CheckboxField(string target, IDictionary attributes)
1703 target = RewriteTargetIfWithinObjectScope(target);
1705 object value = ObtainValue(target);
1707 string trueValue = CommonUtils.ObtainEntryAndRemove(attributes, "trueValue", "true");
1709 bool isChecked;
1711 if (trueValue != "true")
1713 isChecked = AreEqual(value, trueValue);
1715 else
1717 isChecked = ((value != null && value is bool && ((bool)value)) ||
1718 (!(value is bool) && (value != null) &&
1719 (!(value is string) || ((string)value).ToLower() != "false")));
1722 if (isChecked)
1724 if (attributes == null)
1726 attributes = new HybridDictionary(true);
1729 AddChecked(attributes);
1732 ApplyValidation(InputElementType.Checkbox, target, ref attributes);
1734 string id = CreateHtmlId(attributes, target);
1735 string hiddenElementId = id + "H";
1736 string hiddenElementValue = CommonUtils.ObtainEntryAndRemove(attributes, "falseValue", "false");
1738 string result = CreateInputElement("checkbox", id, target, trueValue, attributes);
1740 result += CreateInputElement("hidden", hiddenElementId, target, hiddenElementValue, null);
1742 return result;
1745 #endregion
1747 #region RadioField
1749 /// <summary>
1750 /// Generates a radio input type with the specified
1751 /// value to send to the served in case the element in checked.
1752 /// It will automatically check the radio if the target
1753 /// evaluated value is equal to the specified <c>valueToSend</c>.
1754 /// </summary>
1755 ///
1756 /// <example>
1757 /// Consider the following action code:
1758 ///
1759 /// <code>
1760 /// public void Index()
1761 /// {
1762 /// PropertyBag["mode"] = FileMode.Truncate;
1763 /// }
1764 /// </code>
1765 ///
1766 /// And the following view code:
1767 ///
1768 /// <code lang="none">
1769 /// $Form.RadioField("mode", "Append") FileMode.Append
1770 /// $Form.RadioField("mode", "Create") FileMode.Create
1771 /// $Form.RadioField("mode", "CreateNew") FileMode.CreateNew
1772 /// $Form.RadioField("mode", "Open") FileMode.Open
1773 /// $Form.RadioField("mode", "OpenOrCreate", "%{id='customhtmlid'}") FileMode.OpenOrCreate
1774 /// $Form.RadioField("mode", "Truncate") FileMode.Truncate
1775 /// </code>
1776 ///
1777 /// That is going to output:
1778 ///
1779 /// <code lang="none">
1780 /// &lt;input type=&quot;radio&quot; id=&quot;mode&quot; name=&quot;mode&quot; value=&quot;Append&quot; /&gt; FileMode.Append
1781 /// &lt;input type=&quot;radio&quot; id=&quot;mode&quot; name=&quot;mode&quot; value=&quot;Create&quot; /&gt; FileMode.Create
1782 /// &lt;input type=&quot;radio&quot; id=&quot;mode&quot; name=&quot;mode&quot; value=&quot;CreateNew&quot; /&gt; FileMode.CreateNew
1783 /// &lt;input type=&quot;radio&quot; id=&quot;mode&quot; name=&quot;mode&quot; value=&quot;Open&quot; /&gt; FileMode.Open
1784 /// &lt;input type=&quot;radio&quot; id=&quot;customhtmlid&quot; name=&quot;mode&quot; value=&quot;OpenOrCreate&quot; /&gt; FileMode.OpenOrCreate
1785 /// &lt;input type=&quot;radio&quot; id=&quot;mode&quot; name=&quot;mode&quot; value=&quot;Truncate&quot; checked=&quot;checked&quot; /&gt; FileMode.Truncate
1786 /// </code>
1787 ///
1788 /// </example>
1789 ///
1790 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1791 /// <param name="valueToSend"></param>
1792 /// <returns>The generated form element</returns>
1793 public virtual string RadioField(string target, object valueToSend)
1795 return RadioField(target, valueToSend, null);
1798 /// <summary>
1799 /// Generates a radio input type with the specified
1800 /// value to send to the served in case the element in checked.
1801 /// It will automatically check the radio if the target
1802 /// evaluated value is equal to the specified <c>valueToSend</c>.
1803 /// </summary>
1804 ///
1805 /// <seealso cref="RadioField(string,object)"/>
1806 ///
1807 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1808 /// <param name="valueToSend"></param>
1809 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1810 /// <returns>The generated form element</returns>
1811 public virtual string RadioField(string target, object valueToSend, IDictionary attributes)
1813 target = RewriteTargetIfWithinObjectScope(target);
1815 object value = ObtainValue(target);
1817 bool isChecked = AreEqual(valueToSend, value);
1819 if (isChecked)
1821 if (attributes == null)
1823 attributes = new HybridDictionary(true);
1826 AddChecked(attributes);
1829 return CreateInputElement("radio", target, valueToSend, attributes);
1832 #endregion
1834 #region FileField
1836 /// <summary>
1837 /// Generates an input file element.
1838 /// <para>
1839 /// Dirrently than other operations exposed by this helper,
1840 /// no value is extracted for this operation
1841 /// </para>
1842 /// </summary>
1843 /// <param name="target">The object to be based on when creating the element name.</param>
1844 /// <returns>The generated form element</returns>
1845 public virtual string FileField(string target)
1847 return FileField(target, null);
1850 /// <summary>
1851 /// Generates an input file element.
1852 /// <para>
1853 /// Dirrently than other operations exposed by this helper,
1854 /// no value is extracted for this operation
1855 /// </para>
1856 /// </summary>
1857 /// <param name="target">The object to be based on when creating the element name.</param>
1858 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1859 /// <returns>The generated form element</returns>
1860 public virtual string FileField(string target, IDictionary attributes)
1862 target = RewriteTargetIfWithinObjectScope(target);
1864 ApplyValidation(InputElementType.Text, target, ref attributes);
1866 return CreateInputElement("file", target, string.Empty, attributes);
1869 #endregion
1871 #region Select
1873 /// <summary>
1874 /// Creates a <c>select</c> element and its <c>option</c>s based on the <c>dataSource</c>.
1875 /// If the <c>dataSource</c>
1876 /// elements are complex objects (ie not string or primitives),
1877 /// supply the parameters <c>value</c> and <c>text</c> to the dictionary to make
1878 /// the helper use the specified properties to extract the <c>option</c> value and content respectively.
1879 /// <para>
1880 /// You can also specify the attribute <c>firstoption</c> to force the first option be
1881 /// something like 'please select'. You can set the value of <c>firstoption</c> by specifying the attribute
1882 /// <c>firstoptionvalue</c>. The default value is '0'.
1883 /// </para>
1884 /// <para>
1885 /// Usually the <c>target</c> is a single value and the <c>dataSource</c> is obviously
1886 /// a set with multiple items. The element types tend to be the same. If
1887 /// they are not, you might have to specify the <c>suffix</c> parameters on
1888 /// the <c>attributes</c> as it would not be inferred.
1889 /// </para>
1890 /// <para>
1891 /// The target can also be a set. In this case the intersection will be
1892 /// the initially selected elements.
1893 /// </para>
1894 /// </summary>
1895 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1896 /// <param name="dataSource">The set of available elements</param>
1897 /// <returns>The generated form element</returns>
1898 public virtual string Select(string target, IEnumerable dataSource)
1900 return Select(target, dataSource, null);
1903 /// <summary>
1904 /// Creates a <c>select</c> element and its <c>option</c>s based on the <c>dataSource</c>.
1905 /// If the <c>dataSource</c>
1906 /// elements are complex objects (ie not string or primitives),
1907 /// supply the parameters <c>value</c> and <c>text</c> to the dictionary to make
1908 /// the helper use the specified properties to extract the <c>option</c> value and content respectively.
1909 /// <para>
1910 /// You can also specify the attribute <c>firstoption</c> to force the first option be
1911 /// something like 'please select'. You can set the value of <c>firstoption</c> by specifying the attribute
1912 /// <c>firstoptionvalue</c>. The default value is '0'.
1913 /// </para>
1914 /// <para>
1915 /// Usually the <c>target</c> is a single value and the <c>dataSource</c> is obviously
1916 /// a set with multiple items. The element types tend to be the same. If
1917 /// they are not, you might have to specify the <c>suffix</c> parameters on
1918 /// the <c>attributes</c> as it would not be inferred.
1919 /// </para>
1920 /// <para>
1921 /// The target can also be a set. In this case the intersection will be
1922 /// the initially selected elements.
1923 /// </para>
1924 /// </summary>
1925 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1926 /// <param name="dataSource">The set of available elements</param>
1927 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1928 /// <returns>The generated form element</returns>
1929 public virtual string Select(string target, IEnumerable dataSource, IDictionary attributes)
1931 target = RewriteTargetIfWithinObjectScope(target);
1933 object selectedValue = ObtainValue(target);
1935 return Select(target, selectedValue, dataSource, attributes);
1938 /// <summary>
1939 /// Creates a <c>select</c> element and its <c>option</c>s based on the <c>dataSource</c>.
1940 /// If the <c>dataSource</c>
1941 /// elements are complex objects (ie not string or primitives),
1942 /// supply the parameters <c>value</c> and <c>text</c> to the dictionary to make
1943 /// the helper use the specified properties to extract the <c>option</c> value and content respectively.
1944 /// <para>
1945 /// You can also specify the attribute <c>firstoption</c> to force the first option be
1946 /// something like 'please select'. You can set the value of <c>firstoption</c> by specifying the attribute
1947 /// <c>firstoptionvalue</c>. The default value is '0'.
1948 /// </para>
1949 /// <para>
1950 /// Usually the <c>target</c> is a single value and the <c>dataSource</c> is obviously
1951 /// a set with multiple items. The element types tend to be the same. If
1952 /// they are not, you might have to specify the <c>suffix</c> parameters on
1953 /// the <c>attributes</c> as it would not be inferred.
1954 /// </para>
1955 /// <para>
1956 /// The target can also be a set. In this case the intersection will be
1957 /// the initially selected elements.
1958 /// </para>
1959 /// </summary>
1960 /// <param name="target">The object to get the value from and to be based on to create the element name.</param>
1961 /// <param name="selectedValue"></param>
1962 /// <param name="dataSource">The set of available elements</param>
1963 /// <param name="attributes">Attributes for the FormHelper method and for the html element it generates</param>
1964 /// <returns>The generated form element</returns>
1965 public virtual string Select(string target, object selectedValue, IEnumerable dataSource, IDictionary attributes)
1967 return GenerateSelect(target, selectedValue, dataSource, attributes);
1970 /// <summary>
1971 /// Generates the select.
1972 /// </summary>
1973 /// <param name="target">The target.</param>
1974 /// <param name="selectedValue">The selected value.</param>
1975 /// <param name="dataSource">The data source.</param>
1976 /// <param name="attributes">The attributes.</param>
1977 /// <returns></returns>
1978 protected virtual string GenerateSelect(string target, object selectedValue, IEnumerable dataSource, IDictionary attributes)
1980 string id = CreateHtmlId(target);
1982 ApplyValidation(InputElementType.Select, target, ref attributes);
1984 StringBuilder sb = new StringBuilder();
1985 StringWriter sbWriter = new StringWriter(sb);
1986 HtmlTextWriter writer = new HtmlTextWriter(sbWriter);
1988 string firstOption = null;
1989 string firstOptionValue = null;
1990 bool pascalCaseToWord = false;
1991 string name = target;
1993 if (attributes != null)
1995 firstOption = CommonUtils.ObtainEntryAndRemove(attributes, "firstoption");
1996 firstOptionValue = CommonUtils.ObtainEntryAndRemove(attributes, "firstoptionvalue");
1998 pascalCaseToWord = Convert.ToBoolean(CommonUtils.ObtainEntryAndRemove(attributes, "pascalCaseToWord"));
2000 if (attributes.Contains("name"))
2002 name = (String)attributes["name"];
2003 attributes.Remove("name");
2006 if (attributes.Contains("id"))
2008 id = (String)attributes["id"];
2009 attributes.Remove("id");
2013 OperationState state = SetOperation.IterateOnDataSource(selectedValue, dataSource, attributes);
2015 writer.WriteBeginTag("select");
2016 writer.WriteAttribute("id", id);
2017 writer.WriteAttribute("name", name);
2018 writer.Write(" ");
2019 writer.Write(GetAttributes(attributes));
2020 writer.Write(HtmlTextWriter.TagRightChar);
2021 writer.WriteLine();
2023 if (firstOption != null)
2025 writer.WriteBeginTag("option");
2026 writer.WriteAttribute("value", (firstOptionValue == null) ? "0" : SafeHtmlEncode(firstOptionValue));
2027 writer.Write(HtmlTextWriter.TagRightChar);
2028 writer.Write(SafeHtmlEncode(firstOption));
2029 writer.WriteEndTag("option");
2030 writer.WriteLine();
2033 foreach (SetItem item in state)
2035 writer.WriteBeginTag("option");
2037 if (item.IsSelected)
2039 writer.Write(" selected=\"selected\"");
2042 writer.WriteAttribute("value", SafeHtmlEncode(item.Value));
2043 writer.Write(HtmlTextWriter.TagRightChar);
2045 if (pascalCaseToWord)
2047 writer.Write(SafeHtmlEncode(TextHelper.PascalCaseToWord(item.Text)));
2049 else
2051 writer.Write(SafeHtmlEncode(item.Text));
2054 writer.WriteEndTag("option");
2055 writer.WriteLine();
2058 writer.WriteEndTag("select");
2060 return sbWriter.ToString();
2063 #endregion
2065 #region Field set
2067 /// <summary>
2068 /// Creates a field set element with a legend using the specified name.
2069 /// </summary>
2070 /// <param name="name">The name.</param>
2071 /// <returns></returns>
2072 public virtual string FieldSet(string name)
2074 return "<fieldset><legend>" + name + "</legend>";
2077 /// <summary>
2078 /// Creates an element to close a fieldset element.
2079 /// </summary>
2080 /// <returns></returns>
2081 public virtual string EndFieldSet()
2083 return "</fieldset>";
2086 #endregion
2088 #region Enum
2090 /// <summary>
2091 /// Creates a list of pairs for the enum type.
2092 /// </summary>
2093 /// <param name="enumType">enum type.</param>
2094 /// <returns></returns>
2095 public static Pair<int, string>[] EnumToPairs(Type enumType)
2097 if (enumType == null) throw new ArgumentNullException("enumType");
2098 if (!enumType.IsEnum) throw new ArgumentException("enumType must be an Enum", "enumType");
2100 Array values = Enum.GetValues(enumType);
2101 string[] names = Enum.GetNames(enumType);
2103 List<Pair<int, string>> listOfPairs = new List<Pair<int, string>>();
2104 int index = 0;
2106 foreach (string name in names)
2108 int value = Convert.ToInt32(values.GetValue(index++));
2109 listOfPairs.Add(new Pair<int, string>(value, TextHelper.PascalCaseToWord(name)));
2112 return listOfPairs.ToArray();
2115 #endregion
2117 #region Validation
2119 /// <summary>
2120 /// Configures this FormHelper instance to use the supplied
2121 /// web validator to generate field validation.
2122 /// </summary>
2123 /// <param name="provider">The validation provider.</param>
2124 public virtual void UseWebValidatorProvider(IBrowserValidatorProvider provider)
2126 if (provider == null) throw new ArgumentNullException("provider");
2128 ValidatorProvider = provider;
2131 /// <summary>
2132 /// Configures this FormHelper instance to use Prototype for form fields validation
2133 /// </summary>
2134 public virtual void UsePrototypeValidation()
2136 UseWebValidatorProvider(new PrototypeWebValidator());
2139 /// <summary>
2140 /// Configures this FormHelper instance to use fValidate for form fields validation
2141 /// </summary>
2142 public virtual void UsefValidate()
2144 UseWebValidatorProvider(new FValidateWebValidator());
2147 /// <summary>
2148 /// Configures this FormHelper instance to use Zebda for form fields validation
2149 /// </summary>
2150 public virtual void UseZebdaValidation()
2152 UseWebValidatorProvider(new ZebdaWebValidator());
2155 #endregion
2157 #region private static members
2159 private static void ApplyNumberOnlyOptions(IDictionary attributes)
2161 string list = CommonUtils.ObtainEntryAndRemove(attributes, "exceptions", String.Empty);
2162 string forbid = CommonUtils.ObtainEntryAndRemove(attributes, "forbid", String.Empty);
2164 attributes["onKeyPress"] = "return monorail_formhelper_numberonly(event, [" + list + "], [" + forbid + "]);";
2167 private static void ApplyFilterOptions(IDictionary attributes)
2169 string forbid = CommonUtils.ObtainEntryAndRemove(attributes, "forbid", String.Empty);
2171 attributes["onKeyPress"] = "return monorail_formhelper_inputfilter(event, [" + forbid + "]);";
2174 #endregion