From dea34f0c4a089eaff511eca834f0d06a4132dec5 Mon Sep 17 00:00:00 2001 From: Paul Seal Date: Fri, 5 Nov 2021 10:39:17 +0000 Subject: [PATCH 1/5] Added edit link tag helper with readme description too --- .../Composing/BackofficeUserComposer.cs | 15 ++ Our.Umbraco.TagHelpers/EditLinkTagHelper.cs | 252 ++++++++++++++++++ .../Enums/EditLinkPosition.cs | 10 + .../Services/BackofficeUserAccessor.cs | 51 ++++ .../Services/IBackofficeUserAccessor.cs | 9 + README.md | 107 ++++++++ 6 files changed, 444 insertions(+) create mode 100644 Our.Umbraco.TagHelpers/Composing/BackofficeUserComposer.cs create mode 100644 Our.Umbraco.TagHelpers/EditLinkTagHelper.cs create mode 100644 Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs create mode 100644 Our.Umbraco.TagHelpers/Services/BackofficeUserAccessor.cs create mode 100644 Our.Umbraco.TagHelpers/Services/IBackofficeUserAccessor.cs diff --git a/Our.Umbraco.TagHelpers/Composing/BackofficeUserComposer.cs b/Our.Umbraco.TagHelpers/Composing/BackofficeUserComposer.cs new file mode 100644 index 0000000..2b59df4 --- /dev/null +++ b/Our.Umbraco.TagHelpers/Composing/BackofficeUserComposer.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Our.Umbraco.TagHelpers.Services; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; + +namespace Our.Umbraco.TagHelpers.Composing +{ + public class CustomComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddScoped(); + } + } +} diff --git a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs new file mode 100644 index 0000000..0eba25b --- /dev/null +++ b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs @@ -0,0 +1,252 @@ +using Microsoft.AspNetCore.Razor.TagHelpers; +using Our.Umbraco.TagHelpers.Enums; +using Our.Umbraco.TagHelpers.Services; +using System.Linq; +using System.Text; + +namespace Our.Umbraco.TagHelpers +{ + /// + /// If the user viewing the front end is logged in as an umbraco user + /// then an edit link will display on the front end of the site. This will + /// take you to the umbraco backoffice to edit the current page. + /// + [HtmlTargetElement("our-editlink")] + public class EditLinkTagHelper : TagHelper + { + private readonly IBackofficeUserAccessor _backofficeUserAccessor; + + public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor) + { + _backofficeUserAccessor = backofficeUserAccessor; + } + + /// + /// The id of the current content item. Defaults to 0 + /// + [HtmlAttributeName("content-id")] + public int ContentId { get; set; } = 0; + + /// + /// An enum to say which corner of the screen you would like + /// the edit link to show. Defaults to bottom left. + /// + [HtmlAttributeName("position")] + public EditLinkPosition Position { get; set; } = EditLinkPosition.BottomLeft; + + /// + /// A bool to say whether or not you would like to apply the inline link styles. Defaults to true. + /// + [HtmlAttributeName("apply-inline-link-styles")] + public bool ApplyInlineLinkStyles { get; set; } = true; + + /// + /// The 'Edit' text in the link. Defaults to "Edit" + /// + [HtmlAttributeName("edit-message")] + public string EditMessage { get; set; } = "Edit"; + + /// + /// The CSS colour of the link text. Defaults to #fff + /// + [HtmlAttributeName("link-colour")] + public string LinkColour { get; set; } = "#fff"; + + /// + /// The CSS colour of the link background. Defaults to "#1b264f" + /// + [HtmlAttributeName("link-background-colour")] + public string LinkBackgroundColour { get; set; } = "#1b264f"; + + /// + /// The font size of the link text in pixels. Defaults to 16 + /// + [HtmlAttributeName("font-size")] + public int FontSize { get; set; } = 16; + + /// + /// The padding around the link in pixels. Defaults to 10 + /// + [HtmlAttributeName("link-padding")] + public int LinkPadding { get; set; } = 10; + + /// + /// The border radius of the link in pixels. Defaults to 6 + /// + [HtmlAttributeName("border-radius")] + public int BorderRadius { get; set; } = 6; + + /// + /// The class you would like to add to the link. Defaults to "edit-link-inner" + /// + [HtmlAttributeName("link-class-name")] + public string LinkClassName { get; set; } = "edit-link-inner"; + + /// + /// Whether or not you would like to apply the inline styles for the outer element. Defaults to true + /// + [HtmlAttributeName("apply-inline-outer-element-styles")] + public bool ApplyInlineOuterElementStyles { get; set; } = true; + + /// + /// The margin around the link. Defaults to 10 + /// + [HtmlAttributeName("margin")] + public int Margin { get; set; } = 10; + + /// + /// The zindex of this link block. Defaults to 10000 + /// + [HtmlAttributeName("zindex")] + public int Zindex { get; set; } = 10000; + + /// + /// Override the umbraco edit content url if yours is different + /// + [HtmlAttributeName("umbraco-edit-content-url")] + public string UmbracoEditContentUrl { get; set; } = "/umbraco#/content/content/edit/"; + + /// + /// The class name for the outer element. Defaults to "edit-link-outer" + /// + [HtmlAttributeName("outer-class-name")] + public string OuterClassName { get; set; } = "edit-link-outer"; + + /// + /// The CSS position for the outer element. Defaults to "fixed" + /// + [HtmlAttributeName("outer-position")] + public string OuterPosition { get; set; } = "fixed"; + + /// + /// The CSS position for the link. Defaults to "absolute" + /// + [HtmlAttributeName("link-position")] + public string LinkPosition { get; set; } = "absolute"; + + + public override void Process(TagHelperContext context, TagHelperOutput output) + { + output.TagName = ""; + + if(_backofficeUserAccessor.BackofficeUser != null + && _backofficeUserAccessor.BackofficeUser.AuthenticationType + == global::Umbraco.Cms.Core.Constants.Security.BackOfficeAuthenticationType + && _backofficeUserAccessor.BackofficeUser.Claims != null + && _backofficeUserAccessor.BackofficeUser.Claims.Any(x => + x.Type == global::Umbraco.Cms.Core.Constants.Security.AllowedApplicationsClaimType + && x.Value == global::Umbraco.Cms.Core.Constants.Conventions.PermissionCategories.ContentCategory)) + { + var editLink = $"/umbraco#/content/content/edit/{ContentId}"; + + + + StringBuilder editLinkCode = new StringBuilder(); + + //Render the starting outer div + editLinkCode.Append($""); + + //Render the link + editLinkCode.Append($"{EditMessage}"); + + //Render the closing outer div + editLinkCode.Append($""); + output.Content.SetHtmlContent(editLinkCode.ToString()); + return; + } + else + { + output.SuppressOutput(); + return; + } + } + + /// + /// Helper method to get the link styles + /// + /// The CSS colour of the link text + /// The CSS colour of the link background + /// The padding around the link + /// The font size of the link text + /// The border radius of the link + /// + private static string GetLinkStyles(string linkColour, string linkBackgroundColour, + int linkPadding, int fontSize, int borderRadius) + { + StringBuilder linkStyles = new StringBuilder(); + linkStyles.Append($"color:{linkColour};"); + linkStyles.Append($"background-color:{linkBackgroundColour};"); + linkStyles.Append($"padding:{linkPadding}px;"); + linkStyles.Append($"font-size:{fontSize}px;"); + linkStyles.Append($"border-radius:{borderRadius}px;"); + return linkStyles.ToString(); + } + + /// + /// Helper method to get the outer element styles + /// + /// The CSS position of the outer element + /// The CSS position of the link element + /// The margin around the outer element + /// The zindex of the outer element + /// The padding around the link + /// + private static string GetOuterElementStyles(string outerPosition, EditLinkPosition position, + int margin, int zindex, int linkPadding) + { + linkPadding = linkPadding / 2; + + StringBuilder outerStyles = new StringBuilder(); + + outerStyles.Append("display:block;"); + if (outerPosition == "fixed") + { + switch (position) + { + case EditLinkPosition.TopLeft: + outerStyles.Append($"top:{margin + linkPadding}px;"); + outerStyles.Append($"left:{margin}px;"); + break; + case EditLinkPosition.TopRight: + outerStyles.Append($"top:{margin + linkPadding}px;"); + outerStyles.Append($"right:{margin}px;"); + break; + case EditLinkPosition.BottomRight: + outerStyles.Append($"bottom:{margin + linkPadding}px;"); + outerStyles.Append($"right:{margin}px;"); + break; + case EditLinkPosition.BottomLeft: + outerStyles.Append($"bottom:{margin + linkPadding}px;"); + outerStyles.Append($"left:{margin}px;"); + break; + } + } + + outerStyles.Append($"z-index:{zindex};"); + outerStyles.Append($"position:{outerPosition};"); + + return outerStyles.ToString(); + } + } +} \ No newline at end of file diff --git a/Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs b/Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs new file mode 100644 index 0000000..c6aa986 --- /dev/null +++ b/Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs @@ -0,0 +1,10 @@ +namespace Our.Umbraco.TagHelpers.Enums +{ + public enum EditLinkPosition + { + TopLeft = 0, + TopRight = 1, + BottomRight = 2, + BottomLeft = 3 + } +} diff --git a/Our.Umbraco.TagHelpers/Services/BackofficeUserAccessor.cs b/Our.Umbraco.TagHelpers/Services/BackofficeUserAccessor.cs new file mode 100644 index 0000000..303c7dd --- /dev/null +++ b/Our.Umbraco.TagHelpers/Services/BackofficeUserAccessor.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using System.Security.Claims; +using Umbraco.Extensions; + +namespace Our.Umbraco.TagHelpers.Services +{ + + /// + /// Gets the backoffice user from the cookie + /// Code from Markus Johansson on our.umbraco.com + /// 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 + /// + public class BackofficeUserAccessor : IBackofficeUserAccessor + { + private readonly IOptionsSnapshot _cookieOptionsSnapshot; + private readonly IHttpContextAccessor _httpContextAccessor; + + public BackofficeUserAccessor( + IOptionsSnapshot cookieOptionsSnapshot, + IHttpContextAccessor httpContextAccessor) + { + _cookieOptionsSnapshot = cookieOptionsSnapshot; + _httpContextAccessor = httpContextAccessor; + } + + public ClaimsIdentity BackofficeUser + { + get + { + var httpContext = _httpContextAccessor.HttpContext; + + if (httpContext == null) + return new ClaimsIdentity(); + + CookieAuthenticationOptions cookieOptions = _cookieOptionsSnapshot.Get(global::Umbraco.Cms.Core.Constants.Security.BackOfficeAuthenticationType); + string backOfficeCookie = httpContext.Request.Cookies[cookieOptions.Cookie.Name!]; + + if (string.IsNullOrEmpty(backOfficeCookie)) + return new ClaimsIdentity(); + + AuthenticationTicket unprotected = cookieOptions.TicketDataFormat.Unprotect(backOfficeCookie!); + ClaimsIdentity backOfficeIdentity = unprotected!.Principal.GetUmbracoIdentity(); + + return backOfficeIdentity; + } + } + } +} \ No newline at end of file diff --git a/Our.Umbraco.TagHelpers/Services/IBackofficeUserAccessor.cs b/Our.Umbraco.TagHelpers/Services/IBackofficeUserAccessor.cs new file mode 100644 index 0000000..a6690ff --- /dev/null +++ b/Our.Umbraco.TagHelpers/Services/IBackofficeUserAccessor.cs @@ -0,0 +1,9 @@ +using System.Security.Claims; + +namespace Our.Umbraco.TagHelpers.Services +{ + public interface IBackofficeUserAccessor + { + ClaimsIdentity BackofficeUser { get; } + } +} diff --git a/README.md b/README.md index 02ef2f4..24d6389 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,113 @@ There are two special Member Groups you can use:
Everyone except who is authenticated will see this.
``` +## `` +This is a tag helper element which renders an edit link on the front end if the current user is logged into umbraco. The edit link will go to the current page in the umbraco backoffice. You can override the link text and the umbraco url if you are using a different url for the backoffice. You also have different options for styling the link. + +### Simple Example +This is the most basic example. You need to pass in the id of the content item. The link will render in the bottom right of the screen by default. + +```cshtml + +``` + +### Changing the position example + +This will make the link render on the bottom right of the screen + +```cshtml + +``` + +Here are the full set of attributes and what they do: + +#### Required Attributes: + +**content-id** +Default value: `0` + +This is the id of the content item. + +#### Optional Attributes + +**position** +Default value: `Our.Umbraco.TagHelpers.Enums.EditLinkPosition.BottomLeft` + +An enum to say which corner of the screen you would like the edit link to show. + +**apply-inline-link-styles** +Default value: `true` + +A bool to say whether or not you would like to apply the inline link styles. + +**edit-message** +Default value: `"Edit"` + +The 'Edit' text in the link. + +**link-colour** +Default value: `"#fff"` + +**link-background-colour** +Default value: `"#1b264f"` + +The CSS colour of the link background + +**font-size** +Default value: `16` + +The font size of the link text in pixels + +**link-padding** +Default value: `10` + +The padding around the link in pixels + +**border-radius** +Default value: `6` + +The border radius of the link + +**link-class-name** +Default value: `"edit-link-inner"` + +The class you would like to add to the link + +**apply-inline-outer-element-styles** +Default value: `true` + +Whether or not you would like to apply the inline styles for the outer element + +**margin** +Default value: `10` + +The margin around the link + +**zindex** +Default value: `10000` + +The zindex of this link block + +**umbraco-edit-content-url** +Default value: `"/umbraco#/content/content/edit/"` + +Override the umbraco edit content url if yours is different + +**outer-class-name** +Default value: `"edit-link-outer"` + +The class name for the outer element + +**outer-position** +Default value: `"fixed"` + +The CSS position for the outer element + +**link-position** +Default value: `"absolute"` + +The CSS position for the link + ## Video 📺 [![How to create ASP.NET TagHelpers for Umbraco](https://user-images.githubusercontent.com/1389894/138666925-15475216-239f-439d-b989-c67995e5df71.png)](https://www.youtube.com/watch?v=3fkDs0NwIE8) From d2df93972a124604bd7d34a1641905ea9f2a5309 Mon Sep 17 00:00:00 2001 From: Paul Seal Date: Sun, 7 Nov 2021 23:14:28 +0000 Subject: [PATCH 2/5] simplified the edit link removed all of the styling options and left a bool for use default styles or not updated readme to reflect changes --- Our.Umbraco.TagHelpers/EditLinkTagHelper.cs | 213 +++++++----------- .../Enums/EditLinkPosition.cs | 10 - .../Extensions/ClaimsIdentityExtensions.cs | 27 +++ .../Our.Umbraco.TagHelpers.csproj | 2 +- README.md | 117 +++------- 5 files changed, 137 insertions(+), 232 deletions(-) delete mode 100644 Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs create mode 100644 Our.Umbraco.TagHelpers/Extensions/ClaimsIdentityExtensions.cs diff --git a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs index 0eba25b..bce46a0 100644 --- a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs +++ b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Razor.TagHelpers; -using Our.Umbraco.TagHelpers.Enums; +using Our.Umbraco.TagHelpers.Extensions; using Our.Umbraco.TagHelpers.Services; -using System.Linq; using System.Text; namespace Our.Umbraco.TagHelpers @@ -11,7 +10,7 @@ namespace Our.Umbraco.TagHelpers /// then an edit link will display on the front end of the site. This will /// take you to the umbraco backoffice to edit the current page. /// - [HtmlTargetElement("our-editlink")] + [HtmlTargetElement("our-edit-link")] public class EditLinkTagHelper : TagHelper { private readonly IBackofficeUserAccessor _backofficeUserAccessor; @@ -28,150 +27,99 @@ public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor) public int ContentId { get; set; } = 0; /// - /// An enum to say which corner of the screen you would like - /// the edit link to show. Defaults to bottom left. - /// - [HtmlAttributeName("position")] - public EditLinkPosition Position { get; set; } = EditLinkPosition.BottomLeft; - - /// - /// A bool to say whether or not you would like to apply the inline link styles. Defaults to true. - /// - [HtmlAttributeName("apply-inline-link-styles")] - public bool ApplyInlineLinkStyles { get; set; } = true; - - /// - /// The 'Edit' text in the link. Defaults to "Edit" - /// - [HtmlAttributeName("edit-message")] - public string EditMessage { get; set; } = "Edit"; - - /// - /// The CSS colour of the link text. Defaults to #fff - /// - [HtmlAttributeName("link-colour")] - public string LinkColour { get; set; } = "#fff"; - - /// - /// The CSS colour of the link background. Defaults to "#1b264f" - /// - [HtmlAttributeName("link-background-colour")] - public string LinkBackgroundColour { get; set; } = "#1b264f"; - - /// - /// The font size of the link text in pixels. Defaults to 16 - /// - [HtmlAttributeName("font-size")] - public int FontSize { get; set; } = 16; - - /// - /// The padding around the link in pixels. Defaults to 10 - /// - [HtmlAttributeName("link-padding")] - public int LinkPadding { get; set; } = 10; - - /// - /// The border radius of the link in pixels. Defaults to 6 - /// - [HtmlAttributeName("border-radius")] - public int BorderRadius { get; set; } = 6; - - /// - /// The class you would like to add to the link. Defaults to "edit-link-inner" + /// Override the umbraco edit content url if yours is different /// - [HtmlAttributeName("link-class-name")] - public string LinkClassName { get; set; } = "edit-link-inner"; + [HtmlAttributeName("edit-url")] + public string EditUrl { get; set; } = "/umbraco#/content/content/edit/"; /// - /// Whether or not you would like to apply the inline styles for the outer element. Defaults to true + /// Override the text of the link /// - [HtmlAttributeName("apply-inline-outer-element-styles")] - public bool ApplyInlineOuterElementStyles { get; set; } = true; + [HtmlAttributeName("text")] + public string Text { get; set; } = "Edit"; /// - /// The margin around the link. Defaults to 10 + /// A boolean to say whether or not you would like to use the default styling. /// - [HtmlAttributeName("margin")] - public int Margin { get; set; } = 10; + [HtmlAttributeName("use-default-styles")] + public bool UseDefaultStyles { get; set; } = false; /// - /// The zindex of this link block. Defaults to 10000 + /// Set the id attribute if you want /// - [HtmlAttributeName("zindex")] - public int Zindex { get; set; } = 10000; + [HtmlAttributeName("id")] + public string Id { get; set; } = ""; /// - /// Override the umbraco edit content url if yours is different + /// The class attribute for the link /// - [HtmlAttributeName("umbraco-edit-content-url")] - public string UmbracoEditContentUrl { get; set; } = "/umbraco#/content/content/edit/"; + [HtmlAttributeName("class")] + public string Class { get; set; } = ""; /// - /// The class name for the outer element. Defaults to "edit-link-outer" + /// Set the target attribute if you want. Defaults to _blank /// - [HtmlAttributeName("outer-class-name")] - public string OuterClassName { get; set; } = "edit-link-outer"; + [HtmlAttributeName("target")] + public string Target { get; set; } = "_blank"; /// - /// The CSS position for the outer element. Defaults to "fixed" + /// Add some inline styles to the link if you want /// - [HtmlAttributeName("outer-position")] - public string OuterPosition { get; set; } = "fixed"; + [HtmlAttributeName("style")] + public string Style { get; set; } = ""; /// - /// The CSS position for the link. Defaults to "absolute" + /// Set the title attribute if you want /// - [HtmlAttributeName("link-position")] - public string LinkPosition { get; set; } = "absolute"; - + [HtmlAttributeName("title")] + public string Title { get; set; } = ""; public override void Process(TagHelperContext context, TagHelperOutput output) { + //don't output the tag name as it's not valid HTML output.TagName = ""; - if(_backofficeUserAccessor.BackofficeUser != null - && _backofficeUserAccessor.BackofficeUser.AuthenticationType - == global::Umbraco.Cms.Core.Constants.Security.BackOfficeAuthenticationType - && _backofficeUserAccessor.BackofficeUser.Claims != null - && _backofficeUserAccessor.BackofficeUser.Claims.Any(x => - x.Type == global::Umbraco.Cms.Core.Constants.Security.AllowedApplicationsClaimType - && x.Value == global::Umbraco.Cms.Core.Constants.Conventions.PermissionCategories.ContentCategory)) + //check if the user is logged in to the backoffice + //and they have access to the content section + if(_backofficeUserAccessor.BackofficeUser.IsAllowedToSeeEditLink()) { - var editLink = $"/umbraco#/content/content/edit/{ContentId}"; + var editLinkUrl = $"{EditUrl}{ContentId}"; + StringBuilder editLinkCode = new StringBuilder(); + SetAttributeValue("style", Style, editLinkCode); + if (UseDefaultStyles) + { + //Render the outer div with some inline styles + editLinkCode.Append($""); + } - StringBuilder editLinkCode = new StringBuilder(); + //Add the opening tag of the link + editLinkCode.Append($""); - //Render the link - editLinkCode.Append($"{Text}"); - //Render the inline styles for the link - if (ApplyInlineLinkStyles) + if (UseDefaultStyles) { - string linkStyles = GetLinkStyles(LinkColour, LinkBackgroundColour, LinkPadding, FontSize, BorderRadius); - editLinkCode.Append($"style=\"{linkStyles}\""); + //Add the closing outer div + editLinkCode.Append($""); } - //Render the link text and closing tag - editLinkCode.Append($">{EditMessage}"); - - //Render the closing outer div - editLinkCode.Append($""); + //Set the content of the tag helper output.Content.SetHtmlContent(editLinkCode.ToString()); return; } @@ -182,6 +130,14 @@ public override void Process(TagHelperContext context, TagHelperOutput output) } } + private static void SetAttributeValue(string attributeName, string attributeValue, StringBuilder editLinkCode) + { + if (!string.IsNullOrWhiteSpace(attributeValue)) + { + editLinkCode.Append($" {attributeName}=\"{attributeValue}\""); + } + } + /// /// Helper method to get the link styles /// @@ -191,8 +147,12 @@ public override void Process(TagHelperContext context, TagHelperOutput output) /// The font size of the link text /// The border radius of the link /// - private static string GetLinkStyles(string linkColour, string linkBackgroundColour, - int linkPadding, int fontSize, int borderRadius) + private static string GetLinkStyles( + string linkColour = "#ffffff", + string linkBackgroundColour = "#1b264f", + int linkPadding = 10, + int fontSize = 16, + int borderRadius = 6) { StringBuilder linkStyles = new StringBuilder(); linkStyles.Append($"color:{linkColour};"); @@ -207,40 +167,25 @@ private static string GetLinkStyles(string linkColour, string linkBackgroundColo /// Helper method to get the outer element styles /// /// The CSS position of the outer element - /// The CSS position of the link element /// The margin around the outer element - /// The zindex of the outer element + /// The z-index of the outer element /// The padding around the link /// - private static string GetOuterElementStyles(string outerPosition, EditLinkPosition position, - int margin, int zindex, int linkPadding) + private static string GetOuterElementStyles( + string outerPosition = "fixed", + int margin = 10, + int zindex = 10000, + int linkPadding = 10) { - linkPadding = linkPadding / 2; + linkPadding /= 2; - StringBuilder outerStyles = new StringBuilder(); + var outerStyles = new StringBuilder(); outerStyles.Append("display:block;"); if (outerPosition == "fixed") { - switch (position) - { - case EditLinkPosition.TopLeft: - outerStyles.Append($"top:{margin + linkPadding}px;"); - outerStyles.Append($"left:{margin}px;"); - break; - case EditLinkPosition.TopRight: - outerStyles.Append($"top:{margin + linkPadding}px;"); - outerStyles.Append($"right:{margin}px;"); - break; - case EditLinkPosition.BottomRight: - outerStyles.Append($"bottom:{margin + linkPadding}px;"); - outerStyles.Append($"right:{margin}px;"); - break; - case EditLinkPosition.BottomLeft: - outerStyles.Append($"bottom:{margin + linkPadding}px;"); - outerStyles.Append($"left:{margin}px;"); - break; - } + outerStyles.Append($"bottom:{margin + linkPadding}px;"); + outerStyles.Append($"left:{margin}px;"); } outerStyles.Append($"z-index:{zindex};"); diff --git a/Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs b/Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs deleted file mode 100644 index c6aa986..0000000 --- a/Our.Umbraco.TagHelpers/Enums/EditLinkPosition.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Our.Umbraco.TagHelpers.Enums -{ - public enum EditLinkPosition - { - TopLeft = 0, - TopRight = 1, - BottomRight = 2, - BottomLeft = 3 - } -} diff --git a/Our.Umbraco.TagHelpers/Extensions/ClaimsIdentityExtensions.cs b/Our.Umbraco.TagHelpers/Extensions/ClaimsIdentityExtensions.cs new file mode 100644 index 0000000..2bd13d1 --- /dev/null +++ b/Our.Umbraco.TagHelpers/Extensions/ClaimsIdentityExtensions.cs @@ -0,0 +1,27 @@ +using System.Linq; +using System.Security.Claims; +using Umbraco.Cms.Core; + +namespace Our.Umbraco.TagHelpers.Extensions +{ + public static class ClaimsIdentityExtensions + { + public static bool IsAllowedToSeeEditLink(this ClaimsIdentity identity) + { + return IsLoggedIntoUmbraco(identity) && HasAccessToContentSection(identity); + } + + public static bool IsLoggedIntoUmbraco(this ClaimsIdentity identity) + { + return identity?.AuthenticationType != null + && identity.AuthenticationType == Constants.Security.BackOfficeAuthenticationType; + } + + public static bool HasAccessToContentSection(this ClaimsIdentity identity) + { + return identity?.Claims != null && identity.Claims.Any(x => + x.Type == Constants.Security.AllowedApplicationsClaimType + && x.Value == Constants.Conventions.PermissionCategories.ContentCategory); + } + } +} diff --git a/Our.Umbraco.TagHelpers/Our.Umbraco.TagHelpers.csproj b/Our.Umbraco.TagHelpers/Our.Umbraco.TagHelpers.csproj index 2e843d1..62e5501 100644 --- a/Our.Umbraco.TagHelpers/Our.Umbraco.TagHelpers.csproj +++ b/Our.Umbraco.TagHelpers/Our.Umbraco.TagHelpers.csproj @@ -43,7 +43,7 @@ - + diff --git a/README.md b/README.md index 24d6389..f028ef7 100644 --- a/README.md +++ b/README.md @@ -227,112 +227,55 @@ There are two special Member Groups you can use:
Everyone except who is authenticated will see this.
``` -## `` -This is a tag helper element which renders an edit link on the front end if the current user is logged into umbraco. The edit link will go to the current page in the umbraco backoffice. You can override the link text and the umbraco url if you are using a different url for the backoffice. You also have different options for styling the link. +## `` +This is a tag helper element which renders an edit link on the front end only if the current user is logged into umbraco and has access to the content section. -### Simple Example -This is the most basic example. You need to pass in the id of the content item. The link will render in the bottom right of the screen by default. +The edit link will open the current page in the umbraco backoffice. You can override the link text and the umbraco url if you are using a different url for the backoffice. + +### Simple example +This is the most basic example. You need to pass in the id of the content item using the `content-id` attribute. The link will render wherever you put it in the HTML. ```cshtml - + ``` -### Changing the position example +### Use Default Styles example -This will make the link render on the bottom right of the screen +If you set `use-default-styles` to `true`, it will render the link fixed to the bottom left of the screen with white text and a navy blue background. ```cshtml - + ``` -Here are the full set of attributes and what they do: - -#### Required Attributes: - -**content-id** -Default value: `0` - -This is the id of the content item. - -#### Optional Attributes - -**position** -Default value: `Our.Umbraco.TagHelpers.Enums.EditLinkPosition.BottomLeft` - -An enum to say which corner of the screen you would like the edit link to show. - -**apply-inline-link-styles** -Default value: `true` - -A bool to say whether or not you would like to apply the inline link styles. - -**edit-message** -Default value: `"Edit"` - -The 'Edit' text in the link. - -**link-colour** -Default value: `"#fff"` - -**link-background-colour** -Default value: `"#1b264f"` - -The CSS colour of the link background - -**font-size** -Default value: `16` - -The font size of the link text in pixels +### Changing the link text -**link-padding** -Default value: `10` +You can change the link text by adding a `text` attribute: -The padding around the link in pixels - -**border-radius** -Default value: `6` - -The border radius of the link - -**link-class-name** -Default value: `"edit-link-inner"` - -The class you would like to add to the link - -**apply-inline-outer-element-styles** -Default value: `true` - -Whether or not you would like to apply the inline styles for the outer element - -**margin** -Default value: `10` - -The margin around the link - -**zindex** -Default value: `10000` - -The zindex of this link block - -**umbraco-edit-content-url** -Default value: `"/umbraco#/content/content/edit/"` +```cshtml + +``` -Override the umbraco edit content url if yours is different +If you have a multilingual site you could use a dictionary value: -**outer-class-name** -Default value: `"edit-link-outer"` +```cshtml + +``` -The class name for the outer element +### Change the edit link url -**outer-position** -Default value: `"fixed"` +Perhaps you have changed your umbraco path to something different, you can use the `edit-url` attribute to change the umbraco edit content url: -The CSS position for the outer element +```cshtml + +``` -**link-position** -Default value: `"absolute"` +**Here are the other attributes you can set, just like on a normal `a` tag:** -The CSS position for the link +- id +- class +- target (defaults to `_blank`) +- style +- title ## Video 📺 [![How to create ASP.NET TagHelpers for Umbraco](https://user-images.githubusercontent.com/1389894/138666925-15475216-239f-439d-b989-c67995e5df71.png)](https://www.youtube.com/watch?v=3fkDs0NwIE8) From d3b588a3c12c1cccdb3788f2fa980f19f8f56eb6 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 15 Nov 2021 14:43:19 +0000 Subject: [PATCH 3/5] Refactor to make a little simpler - great work Paul :) --- Our.Umbraco.TagHelpers/EditLinkTagHelper.cs | 107 ++++++-------------- 1 file changed, 32 insertions(+), 75 deletions(-) diff --git a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs index bce46a0..ff4e952 100644 --- a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs +++ b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs @@ -2,6 +2,9 @@ using Our.Umbraco.TagHelpers.Extensions; using Our.Umbraco.TagHelpers.Services; using System.Text; +using Microsoft.AspNetCore.Mvc.Rendering; +using System.Threading.Tasks; +using Umbraco.Cms.Core.Web; namespace Our.Umbraco.TagHelpers { @@ -14,17 +17,19 @@ namespace Our.Umbraco.TagHelpers public class EditLinkTagHelper : TagHelper { private readonly IBackofficeUserAccessor _backofficeUserAccessor; + private IUmbracoContextAccessor _umbracoContextAccessor; - public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor) + public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor, IUmbracoContextAccessor umbracoContextAccessor) { _backofficeUserAccessor = backofficeUserAccessor; + _umbracoContextAccessor = umbracoContextAccessor; } /// - /// The id of the current content item. Defaults to 0 + /// The id of the current content item /// [HtmlAttributeName("content-id")] - public int ContentId { get; set; } = 0; + public int ContentId { get; set; } = int.MinValue; /// /// Override the umbraco edit content url if yours is different @@ -32,95 +37,55 @@ public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor) [HtmlAttributeName("edit-url")] public string EditUrl { get; set; } = "/umbraco#/content/content/edit/"; - /// - /// Override the text of the link - /// - [HtmlAttributeName("text")] - public string Text { get; set; } = "Edit"; - /// /// A boolean to say whether or not you would like to use the default styling. /// [HtmlAttributeName("use-default-styles")] public bool UseDefaultStyles { get; set; } = false; - /// - /// Set the id attribute if you want - /// - [HtmlAttributeName("id")] - public string Id { get; set; } = ""; - - /// - /// The class attribute for the link - /// - [HtmlAttributeName("class")] - public string Class { get; set; } = ""; - - /// - /// Set the target attribute if you want. Defaults to _blank - /// - [HtmlAttributeName("target")] - public string Target { get; set; } = "_blank"; - - /// - /// Add some inline styles to the link if you want - /// - [HtmlAttributeName("style")] - public string Style { get; set; } = ""; - - /// - /// Set the title attribute if you want - /// - [HtmlAttributeName("title")] - public string Title { get; set; } = ""; - - public override void Process(TagHelperContext context, TagHelperOutput output) + public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { - //don't output the tag name as it's not valid HTML - output.TagName = ""; + // Turn into an tag + output.TagName = "a"; + + // An outter wrapper div if we use inbuilt styling + var outerDiv = new TagBuilder("div"); - //check if the user is logged in to the backoffice - //and they have access to the content section - if(_backofficeUserAccessor.BackofficeUser.IsAllowedToSeeEditLink()) + // Check if the user is logged in to the backoffice + // and they have access to the content section + if (_backofficeUserAccessor.BackofficeUser.IsAllowedToSeeEditLink()) { + // Try & get Umbraco Current Node int ID (Only do this if ContentId has NOT been set) + if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext) && ContentId == int.MinValue) + { + ContentId = umbracoContext.PublishedRequest.PublishedContent.Id; + } + + // Backoffice URL to content item var editLinkUrl = $"{EditUrl}{ContentId}"; - StringBuilder editLinkCode = new StringBuilder(); - SetAttributeValue("style", Style, editLinkCode); - if (UseDefaultStyles) { - //Render the outer div with some inline styles - editLinkCode.Append($""); + // Wrap the in a "); + output.PostElement.AppendHtml(outerDiv.RenderEndTag()); } - //Set the content of the tag helper - output.Content.SetHtmlContent(editLinkCode.ToString()); return; } else @@ -130,14 +95,6 @@ public override void Process(TagHelperContext context, TagHelperOutput output) } } - private static void SetAttributeValue(string attributeName, string attributeValue, StringBuilder editLinkCode) - { - if (!string.IsNullOrWhiteSpace(attributeValue)) - { - editLinkCode.Append($" {attributeName}=\"{attributeValue}\""); - } - } - /// /// Helper method to get the link styles /// From cf13e080af10bee695ddecb682fd5f7cf98c63e1 Mon Sep 17 00:00:00 2001 From: Paul Seal Date: Mon, 15 Nov 2021 22:08:48 +0000 Subject: [PATCH 4/5] - updated readme for edit link --- Our.Umbraco.TagHelpers/EditLinkTagHelper.cs | 6 +-- README.md | 49 +++++++++------------ 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs index ff4e952..c4fbb10 100644 --- a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs +++ b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs @@ -1,8 +1,8 @@ -using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Razor.TagHelpers; using Our.Umbraco.TagHelpers.Extensions; using Our.Umbraco.TagHelpers.Services; using System.Text; -using Microsoft.AspNetCore.Mvc.Rendering; using System.Threading.Tasks; using Umbraco.Cms.Core.Web; @@ -48,7 +48,7 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu // Turn into an tag output.TagName = "a"; - // An outter wrapper div if we use inbuilt styling + // An outer wrapper div if we use inbuilt styling var outerDiv = new TagBuilder("div"); // Check if the user is logged in to the backoffice diff --git a/README.md b/README.md index f028ef7..5cf9f13 100644 --- a/README.md +++ b/README.md @@ -230,52 +230,45 @@ There are two special Member Groups you can use: ## `` This is a tag helper element which renders an edit link on the front end only if the current user is logged into umbraco and has access to the content section. -The edit link will open the current page in the umbraco backoffice. You can override the link text and the umbraco url if you are using a different url for the backoffice. +The link will open the current page in the umbraco backoffice. You can override the umbraco url if you are using a different url for the backoffice. ### Simple example -This is the most basic example. You need to pass in the id of the content item using the `content-id` attribute. The link will render wherever you put it in the HTML. +This is the most basic example. The link will render wherever you put it in the HTML. -```cshtml - +```html +Edit ``` -### Use Default Styles example - -If you set `use-default-styles` to `true`, it will render the link fixed to the bottom left of the screen with white text and a navy blue background. +It will output a link link this, where 1057 is the id of the current page: -```cshtml - +```html +Edit ``` -### Changing the link text - -You can change the link text by adding a `text` attribute: - -```cshtml - -``` +### Use Default Styles example -If you have a multilingual site you could use a dictionary value: +If you add an attribute of `use-default-styles`, it will render the link fixed to the bottom left of the screen with white text and a navy blue background. -```cshtml - +```html +Edit ``` -### Change the edit link url +### Change the edit url Perhaps you have changed your umbraco path to something different, you can use the `edit-url` attribute to change the umbraco edit content url: -```cshtml - +```html +Edit ``` -**Here are the other attributes you can set, just like on a normal `a` tag:** +### Open in a new tab + +As the edit link is just an `a` tag, you can add the usual attributes like `target` and `class` etc. +If you want the edit link to open in a new tab, just add the `target="_blank"` attribute. -- id -- class -- target (defaults to `_blank`) -- style -- title +```html +Edit +``` ## Video 📺 [![How to create ASP.NET TagHelpers for Umbraco](https://user-images.githubusercontent.com/1389894/138666925-15475216-239f-439d-b989-c67995e5df71.png)](https://www.youtube.com/watch?v=3fkDs0NwIE8) From dcc7cb15d8a743bb2ae018b229b714e7e77a2ad0 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 16 Nov 2021 09:44:03 +0000 Subject: [PATCH 5/5] Not doing anything async in the end --- Our.Umbraco.TagHelpers/EditLinkTagHelper.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs index c4fbb10..76ed3b4 100644 --- a/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs +++ b/Our.Umbraco.TagHelpers/EditLinkTagHelper.cs @@ -3,7 +3,6 @@ using Our.Umbraco.TagHelpers.Extensions; using Our.Umbraco.TagHelpers.Services; using System.Text; -using System.Threading.Tasks; using Umbraco.Cms.Core.Web; namespace Our.Umbraco.TagHelpers @@ -43,7 +42,7 @@ public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor, IUmbrac [HtmlAttributeName("use-default-styles")] public bool UseDefaultStyles { get; set; } = false; - public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + public override void Process(TagHelperContext context, TagHelperOutput output) { // Turn into an tag output.TagName = "a"; @@ -60,7 +59,7 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu { ContentId = umbracoContext.PublishedRequest.PublishedContent.Id; } - + // Backoffice URL to content item var editLinkUrl = $"{EditUrl}{ContentId}";