1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
18 using System
.Collections
;
19 using System
.Collections
.Generic
;
20 using System
.Collections
.Specialized
;
25 using HtmlTextWriter
= System
.Web
.UI
.HtmlTextWriter
;
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
;
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.
41 /// <seealso xref="DataBindAttribute"/>
44 /// Using simple values:
45 /// <para>On the controller:</para>
48 /// public void MyAction()
50 /// PropertyBag["name"] = "John Doe";
54 /// <para>On the view (using NVelocity syntax)</para>
56 /// <code lang="none">
57 /// $Form.TextField('name') // Renders an input text with value "John Doe"
61 /// Using complex objects:
65 /// public void MyAction()
67 /// PropertyBag["user"] = new User("John Doe");
71 /// <para>On the view (using NVelocity syntax)</para>
73 /// <code lang="none">
74 /// $Form.TextField('user.name') // Renders an input text with value "John Doe"
79 /// <b>Elements generation</b> <br/>
81 /// <list type="table">
83 /// <term>Buttons</term>
85 /// <see cref="Submit(string)"/> <br/>
86 /// <see cref="Button(string)" /> <br/>
87 /// <see cref="ButtonElement(string)" />
92 /// <term>Select</term>
94 /// <see cref="Select(string,IEnumerable)" />
99 /// <term>Text area</term>
101 /// <see cref="TextArea(string)" />
106 /// <term>Hidden field</term>
108 /// <see cref="HiddenField(string)" />
113 /// <term>Checkbox field</term>
115 /// <see cref="CheckboxField(string)" /> <br/>
116 /// <see cref="CreateCheckboxList(string,IEnumerable)" />
121 /// <term>Radio field</term>
123 /// <see cref="RadioField(string,object)" />
128 /// <term>File upload</term>
130 /// <see cref="FileField(string)" />
135 /// <term>Text field</term>
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)"/>
145 /// <term>Password field</term>
147 /// <see cref="PasswordField(string)" /> <br/>
148 /// <see cref="PasswordNumberField(string)" />
153 /// <term>Labels</term>
155 /// <see cref="LabelFor(string,string)" /> <br/>
156 /// <see cref="LabelFor(string,string,IDictionary)"/>
164 /// <b>FormValidation</b> <br/>
165 /// The following operations are related to the Form Validation support:
168 /// <list type="table">
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>
174 /// <term><see cref="AbstractFormRelatedHelper.DisableValidation"/> </term>
175 /// <description>Disables validation altogether</description>
178 /// <term><see cref="UseWebValidatorProvider"/> </term>
179 /// <description>Sets a custom Browser validator provider</description>
182 /// <term><see cref="UsePrototypeValidation"/> </term>
183 /// <description>Configures the helper to use the prototype easy field validation. Must be invoked before FormTag</description>
186 /// <term><see cref="UsefValidate"/> </term>
187 /// <description>Configures the helper to use the fValidate. Deprecated.</description>
190 /// <term><see cref="UseZebdaValidation"/> </term>
191 /// <description>Configures the helper to use the Zebda. Must be invoked before FormTag</description>
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
203 /// For example: mask='2,5',mask_separator='/' will mask the content to '12/34/1234'
206 public class FormHelper
: AbstractFormRelatedHelper
, IServiceEnabledComponent
208 private int formCount
;
209 private string currentFormId
;
214 /// Initializes a new instance of the <see cref="FormHelper"/> class.
222 /// Initializes a new instance of the <see cref="FormHelper"/> class.
223 /// setting the Controller, Context and ControllerContext.
225 /// <param name="engineContext">The engine context.</param>
226 public FormHelper(IEngineContext engineContext
) : base(engineContext
)
231 private void Initialize()
233 ValidatorRegistry
= new CachedValidationRegistry();
234 ValidatorRunner
= new ValidatorRunner(false, ValidatorRegistry
);
235 ValidatorProvider
= new PrototypeWebValidator();
240 #region IServiceEnabledComponent implementation
243 /// Invoked by the framework in order to give a chance to
244 /// obtain other services
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
));
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
);
280 ValidatorRunner
= new ValidatorRunner(false, new CachedValidationRegistry());
287 /// Renders a Javascript library inside a single script tag.
289 /// <returns></returns>
290 public virtual string InstallScripts()
292 return RenderScriptBlockToSource("/MonoRail/Files/FormHelperScript");
295 #region FormTag related
298 /// Creates a form tag based on the parameters.
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
305 /// The action attribute generation will use <see cref="UrlHelper"/>
309 /// <seealso cref="DefaultUrlBuilder.BuildUrl(UrlInfo,IDictionary)"/>
313 /// <code lang="none">
314 /// $Form.FormTag("%{action='Save',id='productform'}")
319 /// <code lang="xml">
320 /// <form method='post' action='/[appdir]/[controller]/Save.[extension]' id='productform'>
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
330 /// <list type="table">
332 /// <term>noaction</term>
333 /// <description>boolean. Disables the generation of an action</description>
336 /// <term>method</term>
337 /// <description>string. The http method to use. Defaults to <c>post</c></description>
341 /// <description>string. The form id.</description>
345 /// More parameters can be accepted depending on the form validation strategy you are using (if any).
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
)
355 // Creates action attribute
356 if (CommonUtils
.ObtainEntryAndRemove(parameters
, "noaction", "false") == "false")
358 url
= UrlHelper
.For(parameters
);
361 return FormTag(url
, parameters
);
365 /// Creates a form tag based on the parameters.
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
372 /// The action attribute generation will use <see cref="UrlHelper"/>
378 /// <code lang="none">
379 /// $Form.FormTag('mytarget.castle', "%{id='productform'}")
384 /// <code lang="xml">
385 /// <form method='post' action='mytarget.castle' id='productform'>
391 /// The following parameters are accepted.
393 /// <list type="table">
395 /// <term>method</term>
396 /// <description>string. The http method to use. Defaults to <c>post</c></description>
400 /// <description>string. The form id.</description>
404 /// More parameters can be accepted depending on the form validation strategy you are using (if any).
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
) :
426 formContent
= "<form action='" + url
+ "' method='" + method
+ "' " +
427 "id='" + currentFormId
+ "' " + GetAttributes(parameters
) + ">";
431 formContent
= "<form method='" + method
+ "' id='" + currentFormId
+ "' " + GetAttributes(parameters
) + ">";
434 return formContent
+ afterFormTag
;
438 /// Generate Ajax form tag for ajax based form submission. Experimental.
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
) :
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
;
498 /// Renders an end form element.
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.
504 /// <returns></returns>
505 public virtual string EndFormTag()
507 string beforeEndTag
= string.Empty
;
509 if (validationConfig
!= null)
511 beforeEndTag
= IsValidationEnabled
?
512 validationConfig
.CreateBeforeFormClosed(currentFormId
) :
516 return beforeEndTag
+ "</form>";
521 #region Object scope related
524 /// Pushes the specified target. Experimental.
526 /// <param name="target">The target.</param>
527 public virtual void Push(string target
)
533 /// Pushes the specified target. Experimental.
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
);
544 objectStack
.Push(new FormScopeInfo(target
, disableValidation
!= "true"));
548 value = ObtainValue(target
+ "type");
552 objectStack
.Push(new FormScopeInfo(target
, disableValidation
!= "true"));
556 throw new ArgumentException("target could not be evaluated during Push operation. Target: " + target
);
562 /// Pops this instance. Experimental.
564 public virtual void Pop()
571 #region Submit and Button related
574 /// Generates an input submit element.
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);
584 /// Generates an input submit element.
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
);
595 /// Generates an graphical submit element.
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);
606 /// Generates an input submit element.
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
);
621 /// Generates an input button element.
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);
631 /// Generates an input button element.
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
);
642 /// Creates a basic button element of type submit.
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);
652 /// Creates a basic button element of the specified type.
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);
663 /// Creates a basic button element of the specified type and with specified attributes.
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
);
676 #region TextFieldValue
679 /// Generates an input text form element
680 /// with the supplied value
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);
691 /// Generates an input text form element
692 /// with the supplied value
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
);
708 /// Generates an input text element.
710 /// The value is extracted from the target (if available)
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"/>
718 /// <code lang="none">
719 /// $Form.TextField('username')
722 /// <code lang="xml">
723 /// <input type='text' name='username' id='username' value='John Doe' />
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"/>
731 /// <code lang="none">
732 /// $Form.TextField('user.name')
735 /// <code lang="xml">
736 /// <input type='text' name='user.name' id='user_name' value='John Doe' />
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);
748 /// Generates an input text element.
750 /// The value is extracted from the target (if available)
754 /// <seealso cref="TextField(string)"/>
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
);
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.
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();
798 #region FilteredTextField
801 /// Generates an input text element with a javascript that prevents the
802 /// chars listed in the forbid attribute from being entered.
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.
810 /// FormHelper.FilteredTextField("product.price", {forbid='46'})
812 /// In this case the key code 46 (period) will not be accepted on the field.
814 /// The value is extracted from the target (if available).
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>
820 /// You must invoke <see cref="FormHelper.InstallScripts"/> before using it.
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
);
841 /// Generates an input text element with a javascript that prevents
842 /// chars other than numbers from being entered.
844 /// The value is extracted from the target (if available)
848 /// <seealso cref="InstallScripts"/>
849 /// <seealso cref="NumberField(string,IDictionary)"/>
852 /// You must include the formhelper javascript functions to use the NumberField.
853 /// See <see cref="InstallScripts"/>
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);
864 /// Generates an input text element with a javascript that prevents
865 /// chars other than numbers from being entered.
867 /// The value is extracted from the target (if available)
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>
876 /// You must include the formhelper javascript functions to use the NumberField.
877 /// See <see cref="InstallScripts"/>
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.
884 /// FormHelper.NumberField("product.price", {exceptions='13,10,11'})
886 /// In this case the key codes 13, 10 and 11 will be accepted on the field.
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.
893 /// FormHelper.NumberField("product.price", {forbid='46'})
895 /// In this case the key code 46 (period) will not be accepted on the field.
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
);
913 #region NumberFieldValue
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
921 /// <seealso cref="InstallScripts"/>
922 /// <seealso cref="NumberField(string,IDictionary)"/>
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>
929 /// You must include the formhelper javascript functions to use the NumberField.
930 /// See <see cref="InstallScripts"/>
932 public virtual string NumberFieldValue(string target
, object value)
934 return NumberFieldValue(target
, value, null);
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
943 /// <seealso cref="InstallScripts"/>
944 /// <seealso cref="NumberField(string,IDictionary)"/>
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>
952 /// You must include the formhelper javascript functions to use the NumberField.
953 /// See <see cref="InstallScripts"/>
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
);
972 /// Generates a textarea element.
974 /// The value is extracted from the target (if available)
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);
985 /// Generates a textarea element.
987 /// The value is extracted from the target (if available)
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
);
1001 /// Generates a textarea element with a specified value.
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
));
1023 #region PasswordField
1026 /// Generates a password input field.
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);
1036 /// Generates a password input field.
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
);
1054 #region PasswordNumberField
1057 /// Generates an input password element with a javascript that prevents
1058 /// chars other than numbers from being entered.
1060 /// The value is extracted from the target (if available)
1064 /// You must invoke <see cref="FormHelper.InstallScripts"/> before using it
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);
1074 /// Generates an input password element with a javascript that prevents
1075 /// chars other than numbers from being entered.
1077 /// The value is extracted from the target (if available)
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.
1085 /// FormHelper.NumberField("product.price", {exceptions='13,10,11'})
1087 /// In this case the key codes 13, 10 and 11 will be accepted on the field.
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.
1094 /// FormHelper.NumberField("product.price", {forbid='46'})
1096 /// In this case the key code 46 (period) will not be accepted on the field.
1099 /// You must invoke <see cref="FormHelper.InstallScripts"/> before using it
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
);
1122 ///<summary>Returns the value for specified target with no additional markup. If no value is obtained
1123 /// an empty string is returned.
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
);
1133 return string.Empty
;
1135 return value.ToString();
1143 /// Generates a label element.
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);
1154 /// Generates a label element.
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();
1191 /// Generates a hidden form element.
1193 /// The value is extracted from the target (if available)
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);
1208 /// Generates a hidden form element with the specified value
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);
1219 /// Generates a hidden form element.
1221 /// The value is extracted from the target (if available)
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
);
1241 /// Generates a hidden form element with the specified value
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
);
1254 #region CheckboxList
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>).
1262 /// The enumerable item will be an element of the <c>dataSource</c>.
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.
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.
1277 /// Consider the following action code:
1279 /// public void Index()
1282 /// PropertyBag["primenumbers"] = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
1284 /// // initial selection
1285 /// PropertyBag["selectedPrimes"] = new int[] { 11, 19 };
1289 /// And the respective view code
1291 /// <code lang="none">
1292 /// #set($items = $FormHelper.CreateCheckboxList("selectedPrimes", $primenumbers))
1294 /// #foreach($elem in $items)
1295 /// $items.Item() $elem
1299 /// That will generates the following html:
1301 /// <code lang="none">
1302 /// <input type="checkbox" id="selectedPrimes_0_" name="selectedPrimes[0]" value="2" /> 2
1303 /// <input type="checkbox" id="selectedPrimes_1_" name="selectedPrimes[1]" value="3" /> 3
1304 /// <input type="checkbox" id="selectedPrimes_2_" name="selectedPrimes[2]" value="5" /> 5
1305 /// <input type="checkbox" id="selectedPrimes_3_" name="selectedPrimes[3]" value="7" /> 7
1306 /// <input type="checkbox" id="selectedPrimes_4_" name="selectedPrimes[4]" value="11" checked="checked" /> 11
1307 /// <input type="checkbox" id="selectedPrimes_5_" name="selectedPrimes[5]" value="13" /> 13
1308 /// <input type="checkbox" id="selectedPrimes_6_" name="selectedPrimes[6]" value="17" /> 17
1309 /// <input type="checkbox" id="selectedPrimes_7_" name="selectedPrimes[7]" value="19" checked="checked" /> 19
1310 /// <input type="checkbox" id="selectedPrimes_8_" name="selectedPrimes[8]" value="23" /> 23
1314 /// To customize the id, you can call the <see cref="CheckboxList.Item(string)"/> overload:
1317 /// <code lang="none">
1318 /// #set($items = $FormHelper.CreateCheckboxList("selectedPrimes", $primenumbers))
1320 /// #foreach($elem in $items)
1321 /// $items.Item("myId${velocityCount}") $Form.LabelFor("myId${velocityCount}", $elem.ToString()) <br/>
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);
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>).
1340 /// The enumerable item will be an element of the <c>dataSource</c>.
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.
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.
1354 /// <seealso cref="CreateCheckboxList(string,IEnumerable)"/>
1357 /// Consider the following action code:
1359 /// public void Index()
1361 /// Category[] categories = new Category[] { new Category(1, "Music"), new Category(2, "Humor"), new Category(3, "Politics") };
1362 /// PropertyBag["categories"] = categories; // datasource
1364 /// Blog blog = new Blog();
1365 /// blog.Categories = new Category[] { new Category(2, "Humor") }; // initial selection
1366 /// PropertyBag["blog"] = blog;
1370 /// And the respective view code
1372 /// <code lang="none">
1373 /// #set($items = $Form.CreateCheckboxList("blog.categories", $categories, "%{value='Id'}"))
1375 /// #foreach($elem in $items)
1376 /// $items.Item() $elem
1380 /// That will generates the following html:
1382 /// <code lang="none">
1383 /// <input type="checkbox" id="blog_categories_0_" name="blog.categories[0].Id" value="1" /> Music
1384 /// <input type="checkbox" id="blog_categories_1_" name="blog.categories[1].Id" value="2" checked="checked" /> Humor
1385 /// <input type="checkbox" id="blog_categories_2_" name="blog.categories[2].Id" value="3" /> Politics
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
);
1404 /// Outputs a checkbox element (for internal use)
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
);
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
);
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.
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>";
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.
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;
1472 /// Initializes a new instance of the <see cref="CheckboxList"/> class.
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();
1493 /// Outputs the Checkbox in the correct state (checked/unchecked) based
1495 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1497 /// <returns>The generated input element</returns>
1498 public string Item()
1504 /// Outputs the Checkbox in the correct state (checked/unchecked) based
1506 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
1508 /// <param name="id">The element id</param>
1509 /// <returns>The generated input element</returns>
1510 public string Item(string id
)
1514 throw new InvalidOperationException("Before rendering a checkbox item, you must use MoveNext");
1519 // Nothing to render
1520 return String
.Empty
;
1525 attributes
["id"] = id
;
1528 return helper
.CheckboxItem(index
, target
, operationState
.TargetSuffix
, CurrentSetItem
, attributes
);
1532 /// Outputs a label for the current checkbox element based on the generated id.
1533 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
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);
1543 /// Outputs a label for the current checkbox element based on the generated id.
1544 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
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
);
1555 /// Outputs a label for the current checkbox element based on the given id.
1556 /// <seealso cref="FormHelper.CreateCheckboxList(string,IEnumerable,IDictionary)"/>
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
)
1566 throw new InvalidOperationException("Before rendering a checkbox item, you must use MoveNext");
1569 if (attributes
== null)
1571 attributes
= new HybridDictionary(true);
1576 // Nothing to render
1577 return String
.Empty
;
1582 attributes
["id"] = id
;
1585 return helper
.CheckboxLabel(index
, target
, operationState
.TargetSuffix
, label
, attributes
);
1589 /// Returns an enumerator that iterates through a collection.
1592 /// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
1594 public IEnumerator
GetEnumerator()
1600 /// Advances the enumerator to the next element of the collection.
1603 /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
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
++;
1617 /// Sets the enumerator to its initial position, which is before the first element in the collection.
1619 /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
1627 /// Gets the current element in the collection.
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; }
1638 /// Gets the current set item.
1640 /// <value>The current set item.</value>
1641 public SetItem CurrentSetItem
1643 get { return enumerator.Current as SetItem; }
1649 #region CheckboxField
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.
1659 /// Consider the following view code:
1661 /// <code lang="none">
1662 /// $Form.CheckboxField('user.disabled')
1665 /// That is going to output:
1667 /// <code lang="none">
1668 /// <input type="checkbox" id="user_disabled" name="user.disabled" value="true" />
1669 /// <input type="hidden" id="user_disabledH" name="user.disabled" value="false" />
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);
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.
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.
1696 /// <seealso cref="CheckboxField(string)"/>
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");
1711 if (trueValue
!= "true")
1713 isChecked
= AreEqual(value, trueValue
);
1717 isChecked
= ((value != null && value is bool && ((bool)value)) ||
1718 (!(value is bool) && (value != null) &&
1719 (!(value is string) || ((string)value).ToLower() != "false")));
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);
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>.
1757 /// Consider the following action code:
1760 /// public void Index()
1762 /// PropertyBag["mode"] = FileMode.Truncate;
1766 /// And the following view code:
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
1777 /// That is going to output:
1779 /// <code lang="none">
1780 /// <input type="radio" id="mode" name="mode" value="Append" /> FileMode.Append
1781 /// <input type="radio" id="mode" name="mode" value="Create" /> FileMode.Create
1782 /// <input type="radio" id="mode" name="mode" value="CreateNew" /> FileMode.CreateNew
1783 /// <input type="radio" id="mode" name="mode" value="Open" /> FileMode.Open
1784 /// <input type="radio" id="customhtmlid" name="mode" value="OpenOrCreate" /> FileMode.OpenOrCreate
1785 /// <input type="radio" id="mode" name="mode" value="Truncate" checked="checked" /> FileMode.Truncate
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);
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>.
1805 /// <seealso cref="RadioField(string,object)"/>
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);
1821 if (attributes
== null)
1823 attributes
= new HybridDictionary(true);
1826 AddChecked(attributes
);
1829 return CreateInputElement("radio", target
, valueToSend
, attributes
);
1837 /// Generates an input file element.
1839 /// Dirrently than other operations exposed by this helper,
1840 /// no value is extracted for this operation
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);
1851 /// Generates an input file element.
1853 /// Dirrently than other operations exposed by this helper,
1854 /// no value is extracted for this operation
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
);
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.
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'.
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.
1891 /// The target can also be a set. In this case the intersection will be
1892 /// the initially selected elements.
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);
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.
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'.
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.
1921 /// The target can also be a set. In this case the intersection will be
1922 /// the initially selected elements.
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
);
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.
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'.
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.
1956 /// The target can also be a set. In this case the intersection will be
1957 /// the initially selected elements.
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
);
1971 /// Generates the select.
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
);
2019 writer
.Write(GetAttributes(attributes
));
2020 writer
.Write(HtmlTextWriter
.TagRightChar
);
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");
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
)));
2051 writer
.Write(SafeHtmlEncode(item
.Text
));
2054 writer
.WriteEndTag("option");
2058 writer
.WriteEndTag("select");
2060 return sbWriter
.ToString();
2068 /// Creates a field set element with a legend using the specified name.
2070 /// <param name="name">The name.</param>
2071 /// <returns></returns>
2072 public virtual string FieldSet(string name
)
2074 return "<fieldset><legend>" + name
+ "</legend>";
2078 /// Creates an element to close a fieldset element.
2080 /// <returns></returns>
2081 public virtual string EndFieldSet()
2083 return "</fieldset>";
2091 /// Creates a list of pairs for the enum type.
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>>();
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();
2120 /// Configures this FormHelper instance to use the supplied
2121 /// web validator to generate field validation.
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
;
2132 /// Configures this FormHelper instance to use Prototype for form fields validation
2134 public virtual void UsePrototypeValidation()
2136 UseWebValidatorProvider(new PrototypeWebValidator());
2140 /// Configures this FormHelper instance to use fValidate for form fields validation
2142 public virtual void UsefValidate()
2144 UseWebValidatorProvider(new FValidateWebValidator());
2148 /// Configures this FormHelper instance to use Zebda for form fields validation
2150 public virtual void UseZebdaValidation()
2152 UseWebValidatorProvider(new ZebdaWebValidator());
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
+ "]);";