3
3
4
4
using System . Diagnostics ;
5
5
using System . Text . Encodings . Web ;
6
+ using Microsoft . AspNetCore . Components . Forms ;
6
7
using Microsoft . AspNetCore . Components . RenderTree ;
7
8
8
9
namespace Microsoft . AspNetCore . Components . HtmlRendering . Infrastructure ;
@@ -14,6 +15,11 @@ public partial class StaticHtmlRenderer
14
15
"area" , "base" , "br" , "col" , "embed" , "hr" , "img" , "input" , "link" , "meta" , "param" , "source" , "track" , "wbr"
15
16
} ;
16
17
18
+ private static readonly CascadingParameterInfo _findFormMappingContext = new CascadingParameterInfo (
19
+ new CascadingParameterAttribute ( ) ,
20
+ string . Empty ,
21
+ typeof ( FormMappingContext ) ) ;
22
+
17
23
private static readonly HtmlEncoder _htmlEncoder = HtmlEncoder . Default ;
18
24
private string ? _closestSelectValueAsString ;
19
25
@@ -29,16 +35,16 @@ protected internal virtual void WriteComponentHtml(int componentId, TextWriter o
29
35
Dispatcher . AssertAccess ( ) ;
30
36
31
37
var frames = GetCurrentRenderTreeFrames ( componentId ) ;
32
- RenderFrames ( output , frames , 0 , frames . Count ) ;
38
+ RenderFrames ( componentId , output , frames , 0 , frames . Count ) ;
33
39
}
34
40
35
- private int RenderFrames ( TextWriter output , ArrayRange < RenderTreeFrame > frames , int position , int maxElements )
41
+ private int RenderFrames ( int componentId , TextWriter output , ArrayRange < RenderTreeFrame > frames , int position , int maxElements )
36
42
{
37
43
var nextPosition = position ;
38
44
var endPosition = position + maxElements ;
39
45
while ( position < endPosition )
40
46
{
41
- nextPosition = RenderCore ( output , frames , position ) ;
47
+ nextPosition = RenderCore ( componentId , output , frames , position ) ;
42
48
if ( position == nextPosition )
43
49
{
44
50
throw new InvalidOperationException ( "We didn't consume any input." ) ;
@@ -50,6 +56,7 @@ private int RenderFrames(TextWriter output, ArrayRange<RenderTreeFrame> frames,
50
56
}
51
57
52
58
private int RenderCore (
59
+ int componentId ,
53
60
TextWriter output ,
54
61
ArrayRange < RenderTreeFrame > frames ,
55
62
int position )
@@ -58,7 +65,7 @@ private int RenderCore(
58
65
switch ( frame . FrameType )
59
66
{
60
67
case RenderTreeFrameType . Element :
61
- return RenderElement ( output , frames , position ) ;
68
+ return RenderElement ( componentId , output , frames , position ) ;
62
69
case RenderTreeFrameType . Attribute :
63
70
throw new InvalidOperationException ( $ "Attributes should only be encountered within { nameof ( RenderElement ) } ") ;
64
71
case RenderTreeFrameType . Text :
@@ -70,17 +77,19 @@ private int RenderCore(
70
77
case RenderTreeFrameType . Component :
71
78
return RenderChildComponent ( output , frames , position ) ;
72
79
case RenderTreeFrameType . Region :
73
- return RenderFrames ( output , frames , position + 1 , frame . RegionSubtreeLength - 1 ) ;
80
+ return RenderFrames ( componentId , output , frames , position + 1 , frame . RegionSubtreeLength - 1 ) ;
74
81
case RenderTreeFrameType . ElementReferenceCapture :
75
82
case RenderTreeFrameType . ComponentReferenceCapture :
83
+ return ++ position ;
76
84
case RenderTreeFrameType . NamedEvent :
85
+ RenderHiddenFieldForNamedSubmitEvent ( componentId , output , frames , position ) ;
77
86
return ++ position ;
78
87
default :
79
88
throw new InvalidOperationException ( $ "Invalid element frame type '{ frame . FrameType } '.") ;
80
89
}
81
90
}
82
91
83
- private int RenderElement ( TextWriter output , ArrayRange < RenderTreeFrame > frames , int position )
92
+ private int RenderElement ( int componentId , TextWriter output , ArrayRange < RenderTreeFrame > frames , int position )
84
93
{
85
94
ref var frame = ref frames . Array [ position ] ;
86
95
output . Write ( '<' ) ;
@@ -120,7 +129,7 @@ private int RenderElement(TextWriter output, ArrayRange<RenderTreeFrame> frames,
120
129
}
121
130
else
122
131
{
123
- afterElement = RenderChildren ( output , frames , afterAttributes , remainingElements ) ;
132
+ afterElement = RenderChildren ( componentId , output , frames , afterAttributes , remainingElements ) ;
124
133
}
125
134
126
135
if ( isSelect )
@@ -153,6 +162,54 @@ private int RenderElement(TextWriter output, ArrayRange<RenderTreeFrame> frames,
153
162
}
154
163
}
155
164
165
+ private void RenderHiddenFieldForNamedSubmitEvent ( int componentId , TextWriter output , ArrayRange < RenderTreeFrame > frames , int namedEventFramePosition )
166
+ {
167
+ // Strictly speaking we could just emit the hidden input unconditionally, but since we currently
168
+ // only intend to support this for "form submit" events, validate that's the case
169
+ if ( TryFindEnclosingElementFrame ( frames , namedEventFramePosition , out var enclosingElementFrameIndex ) )
170
+ {
171
+ ref var enclosingElementFrame = ref frames . Array [ enclosingElementFrameIndex ] ;
172
+ if ( string . Equals ( enclosingElementFrame . ElementName , "form" , StringComparison . OrdinalIgnoreCase ) )
173
+ {
174
+ if ( FindFormMappingContext ( componentId ) is { } formMappingContext )
175
+ {
176
+ var combinedFormName = formMappingContext . GetCombinedFormName (
177
+ frames . Array [ namedEventFramePosition ] . NamedEventAssignedName ) ;
178
+
179
+ output . Write ( "<input type=\" hidden\" name=\" handler\" value=\" " ) ;
180
+ _htmlEncoder . Encode ( output , combinedFormName ) ;
181
+ output . Write ( "\" />" ) ;
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ private FormMappingContext ? FindFormMappingContext ( int forComponentId )
188
+ {
189
+ var componentState = GetComponentState ( forComponentId ) ;
190
+ var supplier = CascadingParameterState . GetMatchingCascadingValueSupplier (
191
+ in _findFormMappingContext ,
192
+ componentState . Renderer ,
193
+ componentState ) ;
194
+
195
+ return ( FormMappingContext ? ) supplier ? . GetCurrentValue ( _findFormMappingContext ) ;
196
+ }
197
+
198
+ private static bool TryFindEnclosingElementFrame ( ArrayRange < RenderTreeFrame > frames , int frameIndex , out int result )
199
+ {
200
+ while ( -- frameIndex >= 0 )
201
+ {
202
+ if ( frames . Array [ frameIndex ] . FrameType == RenderTreeFrameType . Element )
203
+ {
204
+ result = frameIndex ;
205
+ return true ;
206
+ }
207
+ }
208
+
209
+ result = default ;
210
+ return false ;
211
+ }
212
+
156
213
private static int RenderAttributes (
157
214
TextWriter output , ArrayRange < RenderTreeFrame > frames , int position , int maxElements , bool includeValueAttribute , out string ? capturedValueAttribute )
158
215
{
@@ -210,14 +267,14 @@ private static int RenderAttributes(
210
267
return position + maxElements ;
211
268
}
212
269
213
- private int RenderChildren ( TextWriter output , ArrayRange < RenderTreeFrame > frames , int position , int maxElements )
270
+ private int RenderChildren ( int componentId , TextWriter output , ArrayRange < RenderTreeFrame > frames , int position , int maxElements )
214
271
{
215
272
if ( maxElements == 0 )
216
273
{
217
274
return position ;
218
275
}
219
276
220
- return RenderFrames ( output , frames , position , maxElements ) ;
277
+ return RenderFrames ( componentId , output , frames , position , maxElements ) ;
221
278
}
222
279
223
280
private int RenderChildComponent ( TextWriter output , ArrayRange < RenderTreeFrame > frames , int position )
0 commit comments