Wednesday 7 December 2011

Wrapping Images using the Html Agility Pack, TinyMce, Umbraco


Here is an Umbraco related rendering task that most people would probably do in the DOM.

You have an image that was inserted in tinymce. You want to wrap that image tag in some custom markup.

I used the Html Agility pack to do just that (code below)!

I coded in <figure> but you can use anything you like.

In a razor script I just did this:
var newBodyHtml = WrapImages(bodyHtml, "your outer css class", "your inner css class")

/// <summary>
/// Wraps body images in custom markup
/// E.g.
/// Turns <img src="" /> into  <figure class="<cssclassouter>"><a href=""><img src="" class="<cssclassinner>" /></a></figure>
/// </summary>
/// <param name="body"></param>
/// <returns></returns>
string WrapImages(string bodyHtml, string cssClassOuter, string cssClassInner)
{
 var doc = new HtmlAgilityPack.HtmlDocument();
 doc.LoadHtml(bodyHtml);

 // traverse html to find and replace image node
 var q = new Queue<HtmlNode>();
 q.Enqueue(doc.DocumentNode);
 while (q.Count > 0)
 {
  var item = q.Dequeue();
  HtmlNode node = null;

  // found image, need to wrap it!
  if (item.Name == "img")
  {
   // get image src from item
   string imageUrl = item.Attributes["src"].Value;

   // create new node
   node = HtmlTextNode.CreateNode("<figure class=\" + cssClassOuter + "\"><a href=\"" + imageUrl + "\" ><img src=\"" + imageUrl + "\" class=\" + cssClassInner + \" /></a></figure>");

   // set new html
   item.ParentNode.InnerHtml = node.OuterHtml;
  }
  else
  {
   // traverse children
   foreach (var child in item.ChildNodes) { q.Enqueue(child); }
  }
 }
 return doc.DocumentNode.OuterHtml;
}