Skip to content

Instantly share code, notes, and snippets.

@IvanLieckens
Created September 25, 2019 06:23
Show Gist options
  • Save IvanLieckens/baa5aaaeae2f5d5ab55beb4bbab5b4a6 to your computer and use it in GitHub Desktop.
Save IvanLieckens/baa5aaaeae2f5d5ab55beb4bbab5b4a6 to your computer and use it in GitHub Desktop.
Sitecore EXM rewriting of HTML tables to better support Experience Editor while retaining original output
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
<sitecore role:require="Standalone or ContentManagement">
<pipelines>
<mvc.renderRendering>
<processor type="Project.EXM.Pipelines.RenderRendering.ExmTableRewriter, Project.EXM"/>
</mvc.renderRendering>
</pipelines>
</sitecore>
</configuration>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using Sitecore.Mvc.Extensions;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;
namespace Project.EXM.Pipelines.RenderRendering
{
public class ExmTableRewriter : RenderRenderingProcessor
{
public override void Process(RenderRenderingArgs args)
{
if (!Sitecore.Context.PageMode.IsExperienceEditorEditing || !(args.PageContext?.RequestContext?.HttpContext.Request.QueryString?.GetValues("exm")?.Contains("1")).GetValueOrDefault(false))
{
return;
}
StringWriter writer = args.Writer as StringWriter;
if (writer == null)
{
return;
}
RewriteTables(writer);
}
private static void RewriteTables(StringWriter writer)
{
StringBuilder sb = writer.GetStringBuilder();
HtmlDocument doc = LoadDocument(sb);
bool touched = false;
touched |= RewriteTag(doc, "table", "table");
touched |= RewriteTag(doc, "tr", "table-row");
touched |= RewriteTag(doc, "td", "table-cell");
if (touched)
{
FlushWriter(sb, doc);
}
}
private static HtmlDocument LoadDocument(StringBuilder sb)
{
HtmlDocument result = new HtmlDocument();
result.LoadHtml(sb.ToString());
return result;
}
private static void FlushWriter(StringBuilder sb, HtmlDocument doc)
{
using (StringWriter sw = new StringWriter())
{
doc.Save(sw);
sw.Flush();
sb.Clear();
sb.Append(sw);
}
}
private static bool RewriteTag(HtmlDocument doc, string tagName, string style)
{
bool result = false;
HtmlNodeCollection tags = doc.DocumentNode.SelectNodes($"//{tagName}");
if (tags != null && tags.Count > 0)
{
foreach (HtmlNode tag in tags)
{
tag.Name = "div";
AddStyle(tag, "display", style);
RewriteHeight(tag);
RewriteWidth(tag);
RewriteBgcolor(tag);
RewriteAlign(tag);
RewriteValign(tag);
}
result = true;
}
return result;
}
private static void RewriteValign(HtmlNode node)
{
HtmlAttribute attribute = node.Attributes["valign"];
if (attribute != null)
{
AddStyle(node, "vertical-align", attribute.Value);
}
}
private static void RewriteAlign(HtmlNode node)
{
HtmlAttribute attribute = node.Attributes["align"];
if (attribute != null)
{
switch (attribute.Value)
{
case "left":
AddStyle(node, "margin", "0 auto 0 0");
break;
case "right":
AddStyle(node, "margin", "0 0 0 auto");
break;
case "center":
AddStyle(node, "margin", "0 auto");
break;
}
}
}
private static void RewriteBgcolor(HtmlNode node)
{
HtmlAttribute attribute = node.Attributes["bgcolor"];
if (attribute != null)
{
AddStyle(node, "background-color", attribute.Value);
}
}
private static void RewriteWidth(HtmlNode node)
{
HtmlAttribute attribute = node.Attributes["width"];
if (attribute != null)
{
string newValue = attribute.Value.Contains("%") ? attribute.Value : $"{attribute.Value}px";
AddStyle(node, "width", newValue);
}
}
private static void RewriteHeight(HtmlNode node)
{
HtmlAttribute attribute = node.Attributes["height"];
if (attribute != null)
{
string newValue = attribute.Value.Contains("%") ? attribute.Value : $"{attribute.Value}px";
AddStyle(node, "height", newValue);
}
}
private static void AddStyle(HtmlNode node, string key, string value)
{
HtmlAttribute styleAttribute = node.Attributes["style"];
if (styleAttribute != null && !StyleKeys(styleAttribute.Value).Contains(key))
{
styleAttribute.Value = styleAttribute.Value.Trim().WithPostfix(";") + $"{key}: {value};";
}
else
{
node.Attributes.Append("style", $"{key}: {value};");
}
}
private static IEnumerable<string> StyleKeys(string styleValue)
{
string[] styles = styleValue.Split(new[] {";"}, StringSplitOptions.RemoveEmptyEntries);
foreach (string style in styles)
{
string[] keyValuePair = style.Split(':');
yield return keyValuePair[0];
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment