Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Enrico 47 posts 252 karma points
    Jul 11, 2017 @ 12:35
    Enrico
    0

    Umbraco 7.6.3 content picker and the new data-udi

    I am working with the Umbraco Rest API and I am building an Angular JS browser that loads content from Umbraco. The problem comes when I want to replace links inserted using TyneMCE.

    TyneMCE insert link function in Umbraco 7.6.3, saves links to the database with the following format:

    <a data-udi="umb://document/6e5366b90cb74e50a5dac54e650d2105" href="/{localLink:umb://document/6e5366b90cb74e50a5dac54e650d2105}" title="About">about-us</a>
    

    The href element is replaced by the data-udi. Umbraco Rest Api only allows to get contents by id. It is not possible to pass a route or the data-id.

    My questions are:

    1) Is it possible to modify TyneMCE settings in order to create a link with the id and the url of the content, in the following format:

     <a  data-id="1055"  data-url="/"
    data-udi="umb://document/6e5366b90cb74e50a5dac54e650d2105" href="/{localLink:umb://document/6e5366b90cb74e50a5dac54e650d2105}" title="About">about-us</a>
    

    2) How can I get the content id from the new proeprty "udi"?

    3) IPublishedContent does not contain the property 'key'. How can I get the property key of a node?

    Thanks in advance

    Enrico

  • claudio morandi 22 posts 90 karma points
    Jul 17, 2017 @ 07:26
    claudio morandi
    1

    Hello Enrico Did you find a solution about this topic?

  • Enrico 47 posts 252 karma points
    Jul 20, 2017 @ 14:02
    Enrico
    0

    I am still trying to find a good solution, but for now I have this code

    private GuidUdi GetUdi(int id)
    {
        var node = ApplicationContext.Services.ContentService.GetById(id);
                return node?.GetUdi();
     }
    
  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 20, 2017 @ 14:21
    Dave Woestenborghs
    0

    Hi Enrico,

    I would urge you not to use contentservice for retreiving data. The content service hits the database and bypasses the memory cache. This can be performance issue

    Dave

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 20, 2017 @ 10:44
    Dave Woestenborghs
    2

    Hi Enrico,

    You can pass in the guid to Umbraco.ContentQuery.TypedContent() which is avaible in a umbraco API controller. That will return the IPublishedContent item.

    Or you can use Umbraco.GetIdForUdi() and that will return you the id.

    Dave

  • Enrico 47 posts 252 karma points
    Jul 20, 2017 @ 14:05
    Enrico
    0

    Thanks Dave,

    I will give it a try

    This new Udi property is giving me headache.

    Do you know if it's possible modify the way the Rich Text Editor inserts links?

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 20, 2017 @ 14:22
    Dave Woestenborghs
    0

    Do you know if it's possible modify the way the Rich Text Editor inserts links?

    Don't think that is possible. Maybe you can explain what you are trying to do ?

    dave

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 20, 2017 @ 14:23
    Dave Woestenborghs
    0

    Enrico,

    By the way how are you retreving the rich text editor content ? Normally when using the API for getting published content these should be converted to actual links.

    Dave

  • Enrico 47 posts 252 karma points
    Jul 20, 2017 @ 14:38
    Enrico
    0

    My problem is that I am using Umbraco as Rest Api and when I add images stored in Umbraco or link to Umbraco contents I need to replace them.

    My scenario is:

    Umbraco CMS + UmbracoApiController

    In my UmbracoCMS all the pages that have a property called 'body' associated with the Richtext editor (RTE).

    This is an example of what the RTE saves for the property body:

    <p><a data-udi="umb://document/6e5366b90cb74e50a5dac54e650d2105" href="/{localLink:umb://document/6e5366b90cb74e50a5dac54e650d2105}" title="About">Link to About</a></p>
    <p><a data-udi="umb://document/b390252b2ef74c76919048fc8a99dcfc" href="/{localLink:umb://document/b390252b2ef74c76919048fc8a99dcfc}" title="Locations">Link to Locations</a></p>
    <p><a href="https://our.umbraco.org/"><img id="__mcenew" style="display: block; margin-left: auto; margin-right: auto;" src="/media/1002/logo.png" alt="" data-udi="umb://media/99e7581e532c4ae9ac65f9f5a302271e" /></a></p>
    <p> </p>
    

    So when I try to get the html string in an hybrid application (like AngularJs for example) and try to render it, I need to replace the various UDI with an absolute path to the resource.

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 20, 2017 @ 15:02
    Dave Woestenborghs
    1

    But how are you retreiving the content from Umbraco ?

    What API are using ?

    Dave

  • Enrico 47 posts 252 karma points
    Jul 20, 2017 @ 15:19
    Enrico
    0

    I tried with https://our.umbraco.org/documentation/implementation/Rest-Api/

    But a lot of feature are missing. So I started to write my own Implementation.

    This is the code of my controller

    public class MyContentController : UmbracoApiController
        {
            private readonly IExtendedContentService _content;
    
            public MyContentController() : this(new ExtendedContentService())
            {
            }
    
            public MyContentController(IExtendedContentService content)
            {
                this._content = content;
            }
    
            /// <summary>
            ///     Return a tree structure of the pages of the website
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public HttpResponseMessage GetNavigationTree()
            {
                HttpResponseMessage response;
    
                var menuItems = _content.GetNavigationTree();
    
                if (menuItems == null)
                {
                    response = Request.CreateResponse(HttpStatusCode.NotFound);
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.OK, menuItems, new AngularJsonMediaTypeFormatter());
                }
    
                response.Headers.Add("Access-Control-Allow-Origin", "*");
                return response;
            }
    
            /// <summary>
            ///     Return a simple list of web pages
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public HttpResponseMessage GetNavigation()
            {
                HttpResponseMessage response;
    
                var linkItems = _content.GetNavigationList();
    
                if (linkItems == null)
                {
                    response = Request.CreateResponse(HttpStatusCode.NotFound);
    
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.OK, linkItems, new AngularJsonMediaTypeFormatter());
                }
    
                response.Headers.Add("Access-Control-Allow-Origin", "*");
                return response;
            }
    
            /// <summary>
            ///     Returns a node or page of the website
            /// </summary>
            /// <param name="id"></param>
            /// <param name="contentRequest"></param>
            /// <returns></returns>
            [HttpPost]
            public HttpResponseMessage GetNode([FromUri] int id, [FromBody] ContentRequest contentRequest)
            {
                HttpResponseMessage response;
    
                var node = _content.GetNode(id, contentRequest);
    
                if (node == null)
                {
                    response = Request.CreateResponse(HttpStatusCode.NotFound);
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.OK, node, new AngularJsonMediaTypeFormatter());
                }
    
                response.Headers.Add("Access-Control-Allow-Origin", "*");
                response.Headers.Add("Access-Control-Allow-Headers", "*");
                response.Headers.Add("Access-Control-Allow-Methods", "*");
                return response;
            }
        }
    

    This is the code of my ExtendedContentService

     public class ExtendedContentService : UmbracoApiControllerBase, IExtendedContentService
        {
            /// <summary>
            ///     Return a simple list of web pages
            /// </summary>
            /// <returns></returns>
            public List<LinkItem> GetNavigationList()
            {
                var linkItems = new List<LinkItem>();
                var homepage = Umbraco.ContentAtRoot().First();
    
                linkItems.Add(new LinkItem
                {
                    Id = homepage.Id,
                    Name = homepage.Name,
                    ParentId = 0,
                    Url = homepage.Url,
                    NodeUdi = GetUdi(homepage.Id).ToString()
                });
    
                foreach (var item in homepage.Children.Where("Visible"))
                {
                    linkItems.AddRange(GetChildLinks(item));
                }
    
                return linkItems;
            }
    
            /// <summary>
            ///     Return a tree structure of the pages of the website
            /// </summary>
            /// <returns></returns>
            public List<MenuItem> GetNavigationTree()
            {
                var menuItems = new List<MenuItem>();
                var homepage = Umbraco.ContentAtRoot().First();
    
                // menuItems.Add(new MenuItem { name = homepage.Name, link = homepage.id,  url = homepage.Url, subtree = null});
    
                foreach (var item in homepage.Children.Where("Visible"))
                {
                    menuItems.AddRange(GetTreeLinks(item));
                }
    
                return menuItems;
            }
    
            /// <summary>
            ///     Returns a node or page of the website
            /// </summary>
            /// <param name="id"></param>
            /// <param name="contentRequest"></param>
            /// <returns></returns>
            public IContent GetNode(int id, ContentRequest contentRequest)
            {
                if (id > 0)
                {
                    var node = ApplicationContext.Services.ContentService.GetById(id);
    
                    if (!string.IsNullOrEmpty(contentRequest.BaseUrl))
                    {
                        foreach (var prop in node.Properties)
                        {
                            prop.Value = ReplaceImages(prop.Value, contentRequest.BaseUrl);
                            prop.Value = ReplaceLinks(prop.Value, contentRequest.HrefAttribute);
                        }
                    }
    
                    return node;
                }
    
                return null;
            }
    
            /// <summary>
            ///     Recursive function to create a simple list structure
            /// </summary>
            /// <param name="item"></param>
            /// <returns></returns>
            private List<LinkItem> GetChildLinks(dynamic item)
            {
                var newItems = new List<LinkItem>();
    
                newItems.Add(new LinkItem
                {
                    Id = item.Id,
                    Name = item.Name,
                    ParentId = item.ParentId,
                    Url = item.Url,
                    NodeUdi = GetUdi(item.Id).ToString()
                });
    
    
                foreach (var sub in item.Children.Where("Visible"))
                {
                    newItems.AddRange(GetChildLinks(sub));
                }
    
                return newItems;
            }
    
            /// <summary>
            ///     Get Umbraco UDI code
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            private GuidUdi GetUdi(int id)
            {
                var node = ApplicationContext.Services.ContentService.GetById(id);
                return node?.GetUdi();
            }
    
            /// <summary>
            ///     Recursive function to create tree structure of the website pages
            /// </summary>
            /// <param name="item"></param>
            /// <returns></returns>
            private List<MenuItem> GetTreeLinks(dynamic item)
            {
                var newItems = new List<MenuItem>();
                var tempItems = new List<MenuItem>();
    
                foreach (var sub in item.Children.Where("Visible"))
                {
                    tempItems.AddRange(GetTreeLinks(sub));
                }
    
                newItems.Add(new MenuItem
                {
                    name = item.Name,
                    link = tempItems.Any() ? "#" : item.id.ToString(),
                    url = item.Url,
                    subtree = tempItems.Any() ? tempItems : null
                });
    
                return newItems;
            }
    
            /// <summary>
            ///     Replace Umbraco Media Images
            /// </summary>
            /// <param name="value"></param>
            /// <param name="baseUrl"></param>
            /// <returns></returns>
            private object ReplaceImages(object value, string baseUrl)
            {
                if (value != null)
                {
                    var tempReplace = RemoveUdi(value.ToString());
    
                    Regex removeId = new Regex("id=\"([^\"]*)\"", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                    tempReplace = removeId.Replace(tempReplace, "");
    
                    Regex replaceImage = new Regex("/media/([^\"]*)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                    tempReplace = replaceImage.Replace(tempReplace, baseUrl + "${0}");
    
                    return (object) tempReplace;
                }
    
                return null;
            }
    
            /// <summary>
            ///     Remove Umbraco Udi code
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            private static string RemoveUdi(string value)
            {
                if (!string.IsNullOrEmpty(value))
                {
                    Regex regexUdi = new Regex("data-udi=\"([^\"]*)\"", RegexOptions.IgnoreCase | RegexOptions.Singleline);
    
                    return regexUdi.Replace(value, "");
                }
    
                return null;
            }
    
            /// <summary>
            ///     Replace Umbraco links
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            private object ReplaceLinks(object value, string hrefAttribute = "")
            {
                if (value != null)
                {
    
                    string output = RemoveUdi(value.ToString());
                    var links = GetNavigationList();
    
                    string exp = "<a.*?href=[\"']/{localLink:(?<url>.*?)}[\"'].*?>";
                    Regex regexp = new Regex(exp,
                        RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
    
                    if (links != null)
                    {
                        for (Match match = regexp.Match(value.ToString()); match.Success; match = match.NextMatch())
                        {
                            for (int i = 0; i < links.Count; i++)
                            {
    
                                if (match.Groups[1].Value.IndexOf(links[i].NodeUdi, StringComparison.CurrentCultureIgnoreCase) > -1)
                                {
                                    if (string.IsNullOrEmpty(hrefAttribute))
                                    {
                                        output = output.Replace(match.ToString(), "<a href=\"" + links[i].Url + "\">");
                                    }
                                    else
                                    {
                                        output = output.Replace(match.ToString(), "<a href=\"#!" + links[i].Url + "\">");
                                    }
    
    
                                }
                            }
                        }
                    }
    
                    return (object) output;
                }
    
                return null;
            }
        }
    

    This is the best solution I got at the moment. It's not perfect because scraping html strings to replace udi with absoulte path is not that easy.

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 20, 2017 @ 16:04
    Dave Woestenborghs
    1

    Hi Enrico,

    I see you use ApplicationContext.Services.ContentService.GetById(id) a couple of times. You should avoid this. The content service is meant for doing CRUD operations on content and bypasses the cache entirely by hitting the database. This can be a performance issue.

    Better is to use : Umbraco.TypedContent(id). This will return you the IPublishedContent instance direclty from memory. This also has the benefit that RTE properties don't have the UDI links anymore. But contain the actual link to the item.

    Dave

  • Enrico 47 posts 252 karma points
    Jul 20, 2017 @ 16:07
    Enrico
    0

    Thanks Dave.

    I will have a try and I let you know

  • Enrico 47 posts 252 karma points
    Jul 21, 2017 @ 09:14
    Enrico
    0

    Hi Dave,

    I tried the Umbraco.TypedContent(id), but i got serialization issues.

    I will go back using https://our.umbraco.org/documentation/implementation/Rest-Api/ and probabably extend it to implement headless CMS approach.

  • Dave Woestenborghs 3504 posts 12133 karma points MVP 8x admin c-trib
    Jul 21, 2017 @ 10:06
    Dave Woestenborghs
    2

    Hi Enrico,

    Do you return IPublishedContent from your API ? Because that's not serializable. Maybe you can convert it to your own model with only the properties you need.

    Dave

  • Jonathan Roberts 409 posts 1063 karma points
    Feb 16, 2018 @ 10:01
    Jonathan Roberts
    1

    If you have a WYSIWYG and the link output looks like the following:

    <a data-udi="umb://document/6e5366b90cb74e50a5dac54e650d2105" href="/{localLink:umb://document/6e5366b90cb74e50a5dac54e650d2105}" title="About">about-us</a>
    

    pop this at the top of the page:

     string block_Message = string.Empty;
     string html = Model.value.description.ToString();
     block_Message = global::Umbraco.Web.Templates.TemplateUtilities.ParseInternalLinks(html, global::Umbraco.Web.UmbracoContext.Current.UrlProvider);
    

    then wrap the text in a HTML.Raw:

     @Html.Raw(block_Message)
    

    That will then output the href in the link correctly

    Jon

Please Sign in or register to post replies

Write your reply to:

Draft