1
+ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2
+ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
+
4
+ using System ;
5
+ using System . Linq ;
6
+ using Microsoft . AspNet . Mvc . Rendering ;
7
+ using Microsoft . AspNet . Mvc . TagHelpers . Internal ;
8
+ using Microsoft . AspNet . Razor . Runtime . TagHelpers ;
9
+
10
+ namespace Microsoft . AspNet . Mvc . TagHelpers
11
+ {
12
+ /// <summary>
13
+ /// <see cref="ITagHelper"/> implementation targeting <a> elements.
14
+ /// </summary>
15
+ [ TagName ( "a" ) ]
16
+ public class AnchorTagHelper : TagHelper
17
+ {
18
+ private const string RouteAttributePrefix = "route-" ;
19
+
20
+ [ Activate ]
21
+ private ViewContext ViewContext { get ; set ; }
22
+
23
+ [ Activate ]
24
+ private IHtmlGenerator Generator { get ; set ; }
25
+
26
+ /// <summary>
27
+ /// The name of the action method.
28
+ /// </summary>
29
+ /// <remarks>Cannot be provided if <see cref="Route"/> is specified.</remarks>
30
+ public string Action { get ; set ; }
31
+
32
+ /// <summary>
33
+ /// The name of the controller.
34
+ /// </summary>
35
+ /// <remarks>Cannot be provided if <see cref="Route"/> is specified.</remarks>
36
+ public string Controller { get ; set ; }
37
+
38
+ /// <summary>
39
+ /// The protocol for the URL, such as "http" or "https".
40
+ /// </summary>
41
+ public string Protocol { get ; set ; }
42
+
43
+ /// <summary>
44
+ /// The host name for the URL.
45
+ /// </summary>
46
+ public string Host { get ; set ; }
47
+
48
+ /// <summary>
49
+ /// The URL fragment name (the anchor name).
50
+ /// </summary>
51
+ public string Fragment { get ; set ; }
52
+
53
+ /// <summary>
54
+ /// Name of the route.
55
+ /// </summary>
56
+ /// <remarks>Cannot be provided if <see cref="Action"/> or <see cref="Controller"/> is specified.</remarks>
57
+ public string Route { get ; set ; }
58
+
59
+ /// <inheritdoc />
60
+ /// <remarks>Does nothing if user provides a "href" attribute. Cannot specify a "href" attribute AND
61
+ /// <see cref="Action"/>, <see cref="Controller"/> or <see cref="Route"/>.</remarks>
62
+ public override void Process ( TagHelperContext context , TagHelperOutput output )
63
+ {
64
+ // If there's an "href" on the tag it means it's being used as a normal anchor.
65
+ if ( output . Attributes . ContainsKey ( "href" ) )
66
+ {
67
+ if ( Action != null || Controller != null || Route != null )
68
+ {
69
+ // User specified an href AND a Action, Controller or Route; can't determine the href attribute.
70
+ throw new InvalidOperationException (
71
+ Resources . FormatAnchorTagHelper_CannotDetermineHrefOneSpecified (
72
+ nameof ( AnchorTagHelper ) ,
73
+ nameof ( Action ) ,
74
+ nameof ( Controller ) ,
75
+ nameof ( Route ) ) ) ;
76
+ }
77
+
78
+ // User is using the AnchorTagHelper as normal anchor tag, restore any provided attributes.
79
+ RestoreBoundHtmlAttributes ( context , output ) ;
80
+ }
81
+ else
82
+ {
83
+ TagBuilder tagBuilder ;
84
+
85
+ var prefixedValues = TagHelperOutputHelper . PullPrefixedAttributes ( RouteAttributePrefix , output ) ;
86
+
87
+ // Generator.GenerateActionLink || GenerateRouteLink does not accept a Dictionary<string, string> for
88
+ // route values.
89
+ var routeValues = prefixedValues . ToDictionary (
90
+ attribute => attribute . Key . Substring ( RouteAttributePrefix . Length ) ,
91
+ attribute => ( object ) attribute . Value ) ;
92
+
93
+ if ( Route == null )
94
+ {
95
+ tagBuilder = Generator . GenerateActionLink ( linkText : string . Empty ,
96
+ actionName : Action ,
97
+ controllerName : Controller ,
98
+ protocol : Protocol ,
99
+ hostname : Host ,
100
+ fragment : Fragment ,
101
+ routeValues : routeValues ,
102
+ htmlAttributes : null ) ;
103
+ }
104
+ else if ( Action != null || Controller != null )
105
+ {
106
+ // Route and Action or Controller were specified. Can't determine the href attribute.
107
+ throw new InvalidOperationException (
108
+ Resources . FormatAnchorTagHelper_CannotDetermineHrefRouteActionOrControllerSpecified (
109
+ nameof ( AnchorTagHelper ) ,
110
+ nameof ( Route ) ,
111
+ nameof ( Action ) ,
112
+ nameof ( Controller ) ) ) ;
113
+ }
114
+ else
115
+ {
116
+ tagBuilder = Generator . GenerateRouteLink ( linkText : string . Empty ,
117
+ routeName : Route ,
118
+ protocol : Protocol ,
119
+ hostName : Host ,
120
+ fragment : Fragment ,
121
+ routeValues : routeValues ,
122
+ htmlAttributes : null ) ;
123
+ }
124
+
125
+ TagHelperOutputHelper . MergeAttributes ( tagBuilder , output ) ;
126
+ }
127
+ }
128
+
129
+ private void RestoreBoundHtmlAttributes ( TagHelperContext context , TagHelperOutput output )
130
+ {
131
+ if ( Action != null )
132
+ {
133
+ TagHelperOutputHelper . RestoreBoundHtmlAttribute ( nameof ( Action ) , context , output ) ;
134
+ }
135
+
136
+ if ( Controller != null )
137
+ {
138
+ TagHelperOutputHelper . RestoreBoundHtmlAttribute ( nameof ( Controller ) , context , output ) ;
139
+ }
140
+
141
+ if ( Protocol != null )
142
+ {
143
+ TagHelperOutputHelper . RestoreBoundHtmlAttribute ( nameof ( Protocol ) , context , output ) ;
144
+ }
145
+
146
+ if ( Host != null )
147
+ {
148
+ TagHelperOutputHelper . RestoreBoundHtmlAttribute ( nameof ( Host ) , context , output ) ;
149
+ }
150
+
151
+ if ( Fragment != null )
152
+ {
153
+ TagHelperOutputHelper . RestoreBoundHtmlAttribute ( nameof ( Fragment ) , context , output ) ;
154
+ }
155
+
156
+ if ( Route != null )
157
+ {
158
+ TagHelperOutputHelper . RestoreBoundHtmlAttribute ( nameof ( Route ) , context , output ) ;
159
+ }
160
+ }
161
+ }
162
+ }
0 commit comments