Skip to content

Commit dea34f0

Browse files
committed
Added edit link tag helper with readme description too
1 parent d9edf33 commit dea34f0

File tree

6 files changed

+444
-0
lines changed

6 files changed

+444
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Our.Umbraco.TagHelpers.Services;
3+
using Umbraco.Cms.Core.Composing;
4+
using Umbraco.Cms.Core.DependencyInjection;
5+
6+
namespace Our.Umbraco.TagHelpers.Composing
7+
{
8+
public class CustomComposer : IComposer
9+
{
10+
public void Compose(IUmbracoBuilder builder)
11+
{
12+
builder.Services.AddScoped<IBackofficeUserAccessor, BackofficeUserAccessor>();
13+
}
14+
}
15+
}
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
using Microsoft.AspNetCore.Razor.TagHelpers;
2+
using Our.Umbraco.TagHelpers.Enums;
3+
using Our.Umbraco.TagHelpers.Services;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace Our.Umbraco.TagHelpers
8+
{
9+
/// <summary>
10+
/// If the user viewing the front end is logged in as an umbraco user
11+
/// then an edit link will display on the front end of the site. This will
12+
/// take you to the umbraco backoffice to edit the current page.
13+
/// </summary>
14+
[HtmlTargetElement("our-editlink")]
15+
public class EditLinkTagHelper : TagHelper
16+
{
17+
private readonly IBackofficeUserAccessor _backofficeUserAccessor;
18+
19+
public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor)
20+
{
21+
_backofficeUserAccessor = backofficeUserAccessor;
22+
}
23+
24+
/// <summary>
25+
/// The id of the current content item. Defaults to 0
26+
/// </summary>
27+
[HtmlAttributeName("content-id")]
28+
public int ContentId { get; set; } = 0;
29+
30+
/// <summary>
31+
/// An enum to say which corner of the screen you would like
32+
/// the edit link to show. Defaults to bottom left.
33+
/// </summary>
34+
[HtmlAttributeName("position")]
35+
public EditLinkPosition Position { get; set; } = EditLinkPosition.BottomLeft;
36+
37+
/// <summary>
38+
/// A bool to say whether or not you would like to apply the inline link styles. Defaults to true.
39+
/// </summary>
40+
[HtmlAttributeName("apply-inline-link-styles")]
41+
public bool ApplyInlineLinkStyles { get; set; } = true;
42+
43+
/// <summary>
44+
/// The 'Edit' text in the link. Defaults to "Edit"
45+
/// </summary>
46+
[HtmlAttributeName("edit-message")]
47+
public string EditMessage { get; set; } = "Edit";
48+
49+
/// <summary>
50+
/// The CSS colour of the link text. Defaults to #fff
51+
/// </summary>
52+
[HtmlAttributeName("link-colour")]
53+
public string LinkColour { get; set; } = "#fff";
54+
55+
/// <summary>
56+
/// The CSS colour of the link background. Defaults to "#1b264f"
57+
/// </summary>
58+
[HtmlAttributeName("link-background-colour")]
59+
public string LinkBackgroundColour { get; set; } = "#1b264f";
60+
61+
/// <summary>
62+
/// The font size of the link text in pixels. Defaults to 16
63+
/// </summary>
64+
[HtmlAttributeName("font-size")]
65+
public int FontSize { get; set; } = 16;
66+
67+
/// <summary>
68+
/// The padding around the link in pixels. Defaults to 10
69+
/// </summary>
70+
[HtmlAttributeName("link-padding")]
71+
public int LinkPadding { get; set; } = 10;
72+
73+
/// <summary>
74+
/// The border radius of the link in pixels. Defaults to 6
75+
/// </summary>
76+
[HtmlAttributeName("border-radius")]
77+
public int BorderRadius { get; set; } = 6;
78+
79+
/// <summary>
80+
/// The class you would like to add to the link. Defaults to "edit-link-inner"
81+
/// </summary>
82+
[HtmlAttributeName("link-class-name")]
83+
public string LinkClassName { get; set; } = "edit-link-inner";
84+
85+
/// <summary>
86+
/// Whether or not you would like to apply the inline styles for the outer element. Defaults to true
87+
/// </summary>
88+
[HtmlAttributeName("apply-inline-outer-element-styles")]
89+
public bool ApplyInlineOuterElementStyles { get; set; } = true;
90+
91+
/// <summary>
92+
/// The margin around the link. Defaults to 10
93+
/// </summary>
94+
[HtmlAttributeName("margin")]
95+
public int Margin { get; set; } = 10;
96+
97+
/// <summary>
98+
/// The zindex of this link block. Defaults to 10000
99+
/// </summary>
100+
[HtmlAttributeName("zindex")]
101+
public int Zindex { get; set; } = 10000;
102+
103+
/// <summary>
104+
/// Override the umbraco edit content url if yours is different
105+
/// </summary>
106+
[HtmlAttributeName("umbraco-edit-content-url")]
107+
public string UmbracoEditContentUrl { get; set; } = "/umbraco#/content/content/edit/";
108+
109+
/// <summary>
110+
/// The class name for the outer element. Defaults to "edit-link-outer"
111+
/// </summary>
112+
[HtmlAttributeName("outer-class-name")]
113+
public string OuterClassName { get; set; } = "edit-link-outer";
114+
115+
/// <summary>
116+
/// The CSS position for the outer element. Defaults to "fixed"
117+
/// </summary>
118+
[HtmlAttributeName("outer-position")]
119+
public string OuterPosition { get; set; } = "fixed";
120+
121+
/// <summary>
122+
/// The CSS position for the link. Defaults to "absolute"
123+
/// </summary>
124+
[HtmlAttributeName("link-position")]
125+
public string LinkPosition { get; set; } = "absolute";
126+
127+
128+
public override void Process(TagHelperContext context, TagHelperOutput output)
129+
{
130+
output.TagName = "";
131+
132+
if(_backofficeUserAccessor.BackofficeUser != null
133+
&& _backofficeUserAccessor.BackofficeUser.AuthenticationType
134+
== global::Umbraco.Cms.Core.Constants.Security.BackOfficeAuthenticationType
135+
&& _backofficeUserAccessor.BackofficeUser.Claims != null
136+
&& _backofficeUserAccessor.BackofficeUser.Claims.Any(x =>
137+
x.Type == global::Umbraco.Cms.Core.Constants.Security.AllowedApplicationsClaimType
138+
&& x.Value == global::Umbraco.Cms.Core.Constants.Conventions.PermissionCategories.ContentCategory))
139+
{
140+
var editLink = $"/umbraco#/content/content/edit/{ContentId}";
141+
142+
143+
144+
StringBuilder editLinkCode = new StringBuilder();
145+
146+
//Render the starting outer div
147+
editLinkCode.Append($"<div");
148+
editLinkCode.Append($" class=\"{OuterClassName}\"");
149+
150+
//Render the inline styles for the outer div
151+
if (ApplyInlineOuterElementStyles)
152+
{
153+
string outerStyles = GetOuterElementStyles(OuterPosition, Position, Margin, Zindex, LinkPadding);
154+
editLinkCode.Append($" style=\"{outerStyles}\"");
155+
}
156+
editLinkCode.Append($">");
157+
158+
//Render the link
159+
editLinkCode.Append($"<a href=\"{UmbracoEditContentUrl}{ContentId}\"");
160+
editLinkCode.Append($" target=\"_blank\"");
161+
editLinkCode.Append($" class=\"{LinkClassName}\"");
162+
163+
//Render the inline styles for the link
164+
if (ApplyInlineLinkStyles)
165+
{
166+
string linkStyles = GetLinkStyles(LinkColour, LinkBackgroundColour, LinkPadding, FontSize, BorderRadius);
167+
editLinkCode.Append($"style=\"{linkStyles}\"");
168+
}
169+
170+
//Render the link text and closing tag
171+
editLinkCode.Append($">{EditMessage}</a>");
172+
173+
//Render the closing outer div
174+
editLinkCode.Append($"</div>");
175+
output.Content.SetHtmlContent(editLinkCode.ToString());
176+
return;
177+
}
178+
else
179+
{
180+
output.SuppressOutput();
181+
return;
182+
}
183+
}
184+
185+
/// <summary>
186+
/// Helper method to get the link styles
187+
/// </summary>
188+
/// <param name="linkColour">The CSS colour of the link text</param>
189+
/// <param name="linkBackgroundColour">The CSS colour of the link background</param>
190+
/// <param name="linkPadding">The padding around the link</param>
191+
/// <param name="fontSize">The font size of the link text</param>
192+
/// <param name="borderRadius">The border radius of the link</param>
193+
/// <returns></returns>
194+
private static string GetLinkStyles(string linkColour, string linkBackgroundColour,
195+
int linkPadding, int fontSize, int borderRadius)
196+
{
197+
StringBuilder linkStyles = new StringBuilder();
198+
linkStyles.Append($"color:{linkColour};");
199+
linkStyles.Append($"background-color:{linkBackgroundColour};");
200+
linkStyles.Append($"padding:{linkPadding}px;");
201+
linkStyles.Append($"font-size:{fontSize}px;");
202+
linkStyles.Append($"border-radius:{borderRadius}px;");
203+
return linkStyles.ToString();
204+
}
205+
206+
/// <summary>
207+
/// Helper method to get the outer element styles
208+
/// </summary>
209+
/// <param name="outerPosition">The CSS position of the outer element</param>
210+
/// <param name="position">The CSS position of the link element</param>
211+
/// <param name="margin">The margin around the outer element</param>
212+
/// <param name="zindex">The zindex of the outer element</param>
213+
/// <param name="linkPadding">The padding around the link</param>
214+
/// <returns></returns>
215+
private static string GetOuterElementStyles(string outerPosition, EditLinkPosition position,
216+
int margin, int zindex, int linkPadding)
217+
{
218+
linkPadding = linkPadding / 2;
219+
220+
StringBuilder outerStyles = new StringBuilder();
221+
222+
outerStyles.Append("display:block;");
223+
if (outerPosition == "fixed")
224+
{
225+
switch (position)
226+
{
227+
case EditLinkPosition.TopLeft:
228+
outerStyles.Append($"top:{margin + linkPadding}px;");
229+
outerStyles.Append($"left:{margin}px;");
230+
break;
231+
case EditLinkPosition.TopRight:
232+
outerStyles.Append($"top:{margin + linkPadding}px;");
233+
outerStyles.Append($"right:{margin}px;");
234+
break;
235+
case EditLinkPosition.BottomRight:
236+
outerStyles.Append($"bottom:{margin + linkPadding}px;");
237+
outerStyles.Append($"right:{margin}px;");
238+
break;
239+
case EditLinkPosition.BottomLeft:
240+
outerStyles.Append($"bottom:{margin + linkPadding}px;");
241+
outerStyles.Append($"left:{margin}px;");
242+
break;
243+
}
244+
}
245+
246+
outerStyles.Append($"z-index:{zindex};");
247+
outerStyles.Append($"position:{outerPosition};");
248+
249+
return outerStyles.ToString();
250+
}
251+
}
252+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Our.Umbraco.TagHelpers.Enums
2+
{
3+
public enum EditLinkPosition
4+
{
5+
TopLeft = 0,
6+
TopRight = 1,
7+
BottomRight = 2,
8+
BottomLeft = 3
9+
}
10+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Microsoft.AspNetCore.Authentication;
2+
using Microsoft.AspNetCore.Authentication.Cookies;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.Extensions.Options;
5+
using System.Security.Claims;
6+
using Umbraco.Extensions;
7+
8+
namespace Our.Umbraco.TagHelpers.Services
9+
{
10+
11+
/// <summary>
12+
/// Gets the backoffice user from the cookie
13+
/// Code from Markus Johansson on our.umbraco.com
14+
/// https://our.umbraco.com/forum/umbraco-9/106857-how-do-i-determine-if-a-backoffice-user-is-logged-in-from-a-razor-view#comment-334423
15+
/// </summary>
16+
public class BackofficeUserAccessor : IBackofficeUserAccessor
17+
{
18+
private readonly IOptionsSnapshot<CookieAuthenticationOptions> _cookieOptionsSnapshot;
19+
private readonly IHttpContextAccessor _httpContextAccessor;
20+
21+
public BackofficeUserAccessor(
22+
IOptionsSnapshot<CookieAuthenticationOptions> cookieOptionsSnapshot,
23+
IHttpContextAccessor httpContextAccessor)
24+
{
25+
_cookieOptionsSnapshot = cookieOptionsSnapshot;
26+
_httpContextAccessor = httpContextAccessor;
27+
}
28+
29+
public ClaimsIdentity BackofficeUser
30+
{
31+
get
32+
{
33+
var httpContext = _httpContextAccessor.HttpContext;
34+
35+
if (httpContext == null)
36+
return new ClaimsIdentity();
37+
38+
CookieAuthenticationOptions cookieOptions = _cookieOptionsSnapshot.Get(global::Umbraco.Cms.Core.Constants.Security.BackOfficeAuthenticationType);
39+
string backOfficeCookie = httpContext.Request.Cookies[cookieOptions.Cookie.Name!];
40+
41+
if (string.IsNullOrEmpty(backOfficeCookie))
42+
return new ClaimsIdentity();
43+
44+
AuthenticationTicket unprotected = cookieOptions.TicketDataFormat.Unprotect(backOfficeCookie!);
45+
ClaimsIdentity backOfficeIdentity = unprotected!.Principal.GetUmbracoIdentity();
46+
47+
return backOfficeIdentity;
48+
}
49+
}
50+
}
51+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Security.Claims;
2+
3+
namespace Our.Umbraco.TagHelpers.Services
4+
{
5+
public interface IBackofficeUserAccessor
6+
{
7+
ClaimsIdentity BackofficeUser { get; }
8+
}
9+
}

0 commit comments

Comments
 (0)