Razor 模板 <table> 作为基于 IFrame 的所见即所得的有效纯 HTML
Razor template <table> as valid pure HTML for IFrame based WYSIWYG
我有 Razor 模板,客户端可以在基于所见即所得的 IFrame 中设置样式(当前 SCeditor)。
原始构造,如 <p>@Model.Price</p>
或 @(Model.CashOnDelivery ? "cash on delivery" : "transfer")
在 WYSIWYG 中工作正常,但问题出现在 <table>
中。现代浏览器喜欢修复 DOM,而 table 标签之间的 Razor 语法并不是真正有效的 HTML,所以我所拥有的肯定不是我所看到的。
例如
<table border="1">
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
<th>TotalPrice</th>
</tr>
@foreach (var service in Model.Services)
{<tr>
<td>@service.Name</td>
<td>@service.Amount</td>
<td>@service.ItemPrice</td>
<td>@service.TotalPrice</td>
</tr>}
</table>
显示时所见即所得的IFrame DOM变为
@foreach (var service in Model.Services)
{}
<table border="1">
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
<th>TotalPrice</th>
</tr>
<tr>
<td>@service.Name</td>
<td>@service.Amount</td>
<td>@service.ItemPrice</td>
<td>@service.TotalPrice</td>
</tr>
</table>
因此,当用户点击“保存”时,所见即所得会根据固定 DOM 为我提供损坏的代码。 Chrome,Firefox 和 IE 10+ 执行大致相同的更正。
我尝试制作一些 hack,比如将 Razor 隐藏在假属性中,但是
- 源代码中的不平衡 html 标签导致 Razor 编译失败
- 结束标记中的属性无效 HTML 要么
用 JS 填充 table 是行不通的,因为模板通常会直接发送到电子邮件。从 <table>
切换到 <div>
会带走 table 的所见即所得功能,因此这也不是一个好的选择。我可以在一个函数中隐藏 table 生成,但同样,它会阻止它的 WYSIWYGing 样式...
总结一下:我需要继续使用 Razor,<table>
和动态生成行,同时保持所见即所得的功能。最好不要在这个过程中让用户害怕模板。我完全没有想法。
好吧,我想出了一个解决方法。
我将模板更改为
<table border="1">
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
<th>TotalPrice</th>
</tr>
@foreach (var service in Model.Services)
{<tr razor-outer="foreach (var service in Model.Services)">
<td>@service.Name</td>
<td>@service.Amount</td>
<td>@service.ItemPrice</td>
<td>@service.TotalPrice</td>
</tr>}
</table>
然后在所见即所得中显示之前,只需删除具有 razor-outer
属性的 <tr>
节点前后的文本节点。通过在属性中隐藏代码过程是完全可逆的并且所见即所得友好。
public static string PackRazor(string razor)
{
if (string.IsNullOrWhiteSpace(razor))
{
return razor;
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(razor);
string razorOuterXpath = "//*[@razor-outer]";
var nodes = doc.DocumentNode.SelectNodes(razorOuterXpath);
if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
HtmlAttribute razorAttr = node.Attributes["razor-outer"];
var prev = node.PreviousSibling;
var next = node.NextSibling;
if (prev.NodeType == HtmlNodeType.Text && prev.InnerHtml.Contains(razorAttr.Value))
{
node.ParentNode.RemoveChild(prev);
}
if (next.NodeType == HtmlNodeType.Text && next.InnerHtml.Contains("}"))
{
node.ParentNode.RemoveChild(next);
}
}
}
return doc.DocumentNode.OuterHtml;
}
并且在保存模板剃须刀之前可以从属性中恢复
public static string UnpackRazor(string html)
{
if (string.IsNullOrWhiteSpace(html))
{
return html;
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
string razorOuterXpath = "//*[@razor-outer]";
var nodes = doc.DocumentNode.SelectNodes(razorOuterXpath);
if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
HtmlAttribute razorAttr = node.Attributes["razor-outer"];
var newNode = HtmlNode.CreateNode(html);
node.ParentNode.InsertBefore(HtmlNode.CreateNode("@" + razorAttr.Value + "{"), node);
node.ParentNode.InsertAfter(HtmlNode.CreateNode("}"), node);
Console.WriteLine(razorAttr.Value);
}
}
return doc.DocumentNode.OuterHtml;
}
我有 Razor 模板,客户端可以在基于所见即所得的 IFrame 中设置样式(当前 SCeditor)。
原始构造,如 <p>@Model.Price</p>
或 @(Model.CashOnDelivery ? "cash on delivery" : "transfer")
在 WYSIWYG 中工作正常,但问题出现在 <table>
中。现代浏览器喜欢修复 DOM,而 table 标签之间的 Razor 语法并不是真正有效的 HTML,所以我所拥有的肯定不是我所看到的。
例如
<table border="1">
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
<th>TotalPrice</th>
</tr>
@foreach (var service in Model.Services)
{<tr>
<td>@service.Name</td>
<td>@service.Amount</td>
<td>@service.ItemPrice</td>
<td>@service.TotalPrice</td>
</tr>}
</table>
显示时所见即所得的IFrame DOM变为
@foreach (var service in Model.Services)
{}
<table border="1">
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
<th>TotalPrice</th>
</tr>
<tr>
<td>@service.Name</td>
<td>@service.Amount</td>
<td>@service.ItemPrice</td>
<td>@service.TotalPrice</td>
</tr>
</table>
因此,当用户点击“保存”时,所见即所得会根据固定 DOM 为我提供损坏的代码。 Chrome,Firefox 和 IE 10+ 执行大致相同的更正。
我尝试制作一些 hack,比如将 Razor 隐藏在假属性中,但是
- 源代码中的不平衡 html 标签导致 Razor 编译失败
- 结束标记中的属性无效 HTML 要么
用 JS 填充 table 是行不通的,因为模板通常会直接发送到电子邮件。从 <table>
切换到 <div>
会带走 table 的所见即所得功能,因此这也不是一个好的选择。我可以在一个函数中隐藏 table 生成,但同样,它会阻止它的 WYSIWYGing 样式...
总结一下:我需要继续使用 Razor,<table>
和动态生成行,同时保持所见即所得的功能。最好不要在这个过程中让用户害怕模板。我完全没有想法。
好吧,我想出了一个解决方法。
我将模板更改为
<table border="1">
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
<th>TotalPrice</th>
</tr>
@foreach (var service in Model.Services)
{<tr razor-outer="foreach (var service in Model.Services)">
<td>@service.Name</td>
<td>@service.Amount</td>
<td>@service.ItemPrice</td>
<td>@service.TotalPrice</td>
</tr>}
</table>
然后在所见即所得中显示之前,只需删除具有 razor-outer
属性的 <tr>
节点前后的文本节点。通过在属性中隐藏代码过程是完全可逆的并且所见即所得友好。
public static string PackRazor(string razor)
{
if (string.IsNullOrWhiteSpace(razor))
{
return razor;
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(razor);
string razorOuterXpath = "//*[@razor-outer]";
var nodes = doc.DocumentNode.SelectNodes(razorOuterXpath);
if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
HtmlAttribute razorAttr = node.Attributes["razor-outer"];
var prev = node.PreviousSibling;
var next = node.NextSibling;
if (prev.NodeType == HtmlNodeType.Text && prev.InnerHtml.Contains(razorAttr.Value))
{
node.ParentNode.RemoveChild(prev);
}
if (next.NodeType == HtmlNodeType.Text && next.InnerHtml.Contains("}"))
{
node.ParentNode.RemoveChild(next);
}
}
}
return doc.DocumentNode.OuterHtml;
}
并且在保存模板剃须刀之前可以从属性中恢复
public static string UnpackRazor(string html)
{
if (string.IsNullOrWhiteSpace(html))
{
return html;
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
string razorOuterXpath = "//*[@razor-outer]";
var nodes = doc.DocumentNode.SelectNodes(razorOuterXpath);
if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
HtmlAttribute razorAttr = node.Attributes["razor-outer"];
var newNode = HtmlNode.CreateNode(html);
node.ParentNode.InsertBefore(HtmlNode.CreateNode("@" + razorAttr.Value + "{"), node);
node.ParentNode.InsertAfter(HtmlNode.CreateNode("}"), node);
Console.WriteLine(razorAttr.Value);
}
}
return doc.DocumentNode.OuterHtml;
}