@@ -53,11 +53,13 @@ public class InputTagHelper : TagHelper
53
53
{ "time" , "{0:HH:mm:ss.fff}" } ,
54
54
} ;
55
55
56
+ // Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
56
57
[ Activate ]
57
- private IHtmlGenerator Generator { get ; set ; }
58
+ protected internal IHtmlGenerator Generator { get ; set ; }
58
59
60
+ // Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
59
61
[ Activate ]
60
- private ViewContext ViewContext { get ; set ; }
62
+ protected internal ViewContext ViewContext { get ; set ; }
61
63
62
64
/// <summary>
63
65
/// An expression to be evaluated against the current model.
@@ -70,28 +72,34 @@ public class InputTagHelper : TagHelper
70
72
/// attribute to that formatted <see cref="string"/>.
71
73
/// </summary>
72
74
/// <remarks>
73
- /// Used only if <see cref="Value "/> is <c>null</c> and <see cref="Process"/> calls
75
+ /// Used only the calculated "type" attribute is "text" (the most common value) e.g.
76
+ /// <see cref="InputTypeName"/> is "String". That is, <see cref="Format"/> is used when calling
74
77
/// <see cref="IHtmlGenerator.GenerateTextBox"/>.
75
78
/// </remarks>
76
79
public string Format { get ; set ; }
77
80
78
81
/// <summary>
79
- /// The type of the <input> element. Passed through to the generated HTML in all cases. Also used to
80
- /// determine the <see cref="IHtmlGenerator"/> helper <see cref="Process"/> will call and the default
81
- /// <see cref="Format"/> value.
82
+ /// The type of the <input> element.
82
83
/// </summary>
84
+ /// <remarks>
85
+ /// Passed through to the generated HTML in all cases. Also used to determine the <see cref="IHtmlGenerator"/>
86
+ /// helper to call and the default <see cref="Format"/> value (when calling
87
+ /// <see cref="IHtmlGenerator.GenerateTextBox"/>).
88
+ /// </remarks>
83
89
[ HtmlAttributeName ( "type" ) ]
84
90
public string InputTypeName { get ; set ; }
85
91
86
92
/// <summary>
87
- /// The value of the <input> element. Passed through to the generated HTML in all cases. Also used to
88
- /// determine the generated "checked" attribute if <see cref="InputTypeName"/> is "radio".
93
+ /// The value of the <input> element.
89
94
/// </summary>
90
- /// <remarks>Must not be <c>null</c> if <see cref="InputTypeName"/> is "radio".</remarks>
95
+ /// <remarks>
96
+ /// Passed through to the generated HTML in all cases. Also used to determine the generated "checked" attribute
97
+ /// if <see cref="InputTypeName"/> is "radio". Must not be <c>null</c> in that case.
98
+ /// </remarks>
91
99
public string Value { get ; set ; }
92
100
93
101
/// <inheritdoc />
94
- /// <remarks>Does nothing unless user binds "for" attribute in Razor source. </remarks>
102
+ /// <remarks>Does nothing if <see cref="For"/> is <c>null</c> </remarks>
95
103
public override void Process ( TagHelperContext context , TagHelperOutput output )
96
104
{
97
105
// Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying
@@ -112,6 +120,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
112
120
if ( Format != null )
113
121
{
114
122
throw new InvalidOperationException ( Resources . FormatInputTagHelper_UnableToFormat (
123
+ "<input>" ,
115
124
nameof ( For ) . ToLowerInvariant ( ) ,
116
125
nameof ( Format ) . ToLowerInvariant ( ) ) ) ;
117
126
}
@@ -124,6 +133,8 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
124
133
if ( metadata == null )
125
134
{
126
135
throw new InvalidOperationException ( Resources . FormatTagHelpers_NoProvidedMetadata (
136
+ "<input>" ,
137
+ nameof ( For ) . ToLowerInvariant ( ) ,
127
138
nameof ( IModelMetadataProvider ) ,
128
139
For . Name ) ) ;
129
140
}
@@ -143,7 +154,9 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
143
154
if ( ! string . IsNullOrEmpty ( inputType ) )
144
155
{
145
156
// inputType may be more specific than default the generator chooses below.
146
- if ( ! output . Attributes . ContainsKey ( "type" ) )
157
+ // TODO: Use Attributes.ContainsKey once aspnet/Razor#186 is fixed.
158
+ if ( ! output . Attributes . Any (
159
+ item => string . Equals ( "type" , item . Key , StringComparison . OrdinalIgnoreCase ) ) )
147
160
{
148
161
output . Attributes [ "type" ] = inputType ;
149
162
}
@@ -186,6 +199,8 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
186
199
187
200
if ( tagBuilder != null )
188
201
{
202
+ // This TagBuilder contains the one <input/> element of interest. Since this is not the "checkbox"
203
+ // special -case, output is a self-closing element and can merge the TagBuilder in directly.
189
204
output . SelfClosing = true ;
190
205
output . Merge ( tagBuilder ) ;
191
206
}
@@ -197,10 +212,11 @@ private void GenerateCheckBox(ModelMetadata metadata, TagHelperOutput output)
197
212
if ( typeof ( bool ) != metadata . RealModelType )
198
213
{
199
214
throw new InvalidOperationException ( Resources . FormatInputTagHelper_InvalidExpressionResult (
200
- metadata . RealModelType . FullName ,
215
+ "<input>" ,
201
216
nameof ( For ) . ToLowerInvariant ( ) ,
217
+ metadata . RealModelType . FullName ,
202
218
typeof ( bool ) . FullName ,
203
- nameof ( InputTypeName ) . ToLowerInvariant ( ) ,
219
+ "type" ,
204
220
"checkbox" ) ) ;
205
221
}
206
222
@@ -239,6 +255,7 @@ private TagBuilder GenerateRadio(ModelMetadata metadata)
239
255
if ( Value == null )
240
256
{
241
257
throw new InvalidOperationException ( Resources . FormatInputTagHelper_ValueRequired (
258
+ "<input>" ,
242
259
nameof ( Value ) . ToLowerInvariant ( ) ,
243
260
"type" ,
244
261
"radio" ) ) ;
0 commit comments