Link to page where Shortcut type is set to Shortcut to page on another website and open the link in a new window doesn't open in new window

Vote:
 

Hi, 

We are having issues in the scenario where an editor is setting a page shortcut to type: "Shortcut to page on another website" and then Open in to "Open the link in a new window" and then links to this specific page from within TinyMCE on any other page. They expect the target of that anchor link to be "_blank", but target attribute is not rendered unless they specify it from the tinymce link editor too. 

Is there any way for us developers to change the rendering of the anchor tag, or would this rather be considered a bug in episerver/tiny? 

Tested in Episerver version 11.12.0 and Episerver.CMS.TinyMce 2.8.0

#215761
Jan 13, 2020 10:03
Vote:
 

Hi Fredrik,

As far as I'm aware, there's no out of the box way to do this but it is possible to do programmatically. You can create your own views to render content properties so, assuming you'd want this to apply to all XhtmlString properties, you can create a view called XhtmlString.cshtml in ~/Views/Shared/DisplayTemplates/ and modify the value of that property prior to rendering it like this:

@using EPiServer.Editor
@using EPiServer.Web.Mvc.Html
@model EPiServer.Core.XhtmlString

@{
    if (PageEditing.PageIsInEditMode)
    {
        Html.RenderXhtmlString(Model);
    }
    else
    {
        Html.RenderXhtmlString(Model.FixLinkTargets());
    }
}

To process the XhtmlString value so that it checks the content being linked and adds the appropriate target tag, I'd suggest using HTMLAgilityPack (nuget package) and using it to extract links. You can then use the IUrlResolver to get the content associated with the link and check its TargetFrameName value, setting any non-blank values to the target attribute (if a value's not already been set) like this:

public static class XhtmlStringHelpers
{
    public static XhtmlString FixLinkTargets(this XhtmlString xhtmlString)
    {
        if (xhtmlString == null)
        {
            return null;
        }

        var urlresolver = ServiceLocator.Current.GetInstance<IUrlResolver>();

        //use HTMLAgilityPack to get link tags
        var doc = new HtmlDocument();
        doc.LoadHtml(xhtmlString.ToInternalString());
        var linkTags = doc.DocumentNode.SelectNodes("//a");

        //no links = no further processing
        if (linkTags == null)
        {
            return xhtmlString;
        }

        foreach (var linkTag in linkTags)
        {
            var url = linkTag.GetAttributeValue("href", string.Empty);
            var target = linkTag.GetAttributeValue("target", string.Empty);

            //only process non-blank internal URLs without a target already set
            if (string.IsNullOrEmpty(url) || url.Contains("://") || !string.IsNullOrEmpty(target))
            {
                continue;
            }

            var urlBuilder = new UrlBuilder(url);
            var content = urlresolver.Route(urlBuilder);
            if (content == null)
            {
                continue;
            }
            if (content is PageData page && !string.IsNullOrEmpty(page.TargetFrameName))
            {
                linkTag.SetAttributeValue("target", page.TargetFrameName);
            }
        }

        return new XhtmlString(doc.DocumentNode.InnerHtml);
    }
}
#215802
Jan 14, 2020 15:02
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.