使用JavaScript在DOM中展平嵌套跨度以优化HTML编辑器输出

时间:2013-09-19 20:51:00

标签: javascript html dom

我需要使用JavaScript重新格式化输入HTML,以便生成的输出HTML始终是一系列<p>个节点,其中只包含 一个或多个<span>节点,每个节点{ {1}}节点应该只包含一个 <span>节点。

为了提供示例,我想转换如下所示的HTML:

#text

对于看起来像这样的HTML:

<p style="color:red">This is line #1</p>
<p style="color:blue"><span style="color:yellow"><span style="color:red">This is</span> line #2</span></p>
<p style="color:blue"><span style="color:yellow"><span style="color:green">This is line #3</span></span>
<p style="color:blue"><span style="color:yellow">This is</span><span style="color:red">line #4</span></span></p>

附加的,有点切线的信息:

  • 该文本位于TinyMCE编辑器中。 HTML需要符合这种模式,以使应用程序更加可用,并为PDF输出引擎提供可用的HTML(如果HTMl过于复杂,<p style="color:red"><span style="color:red">This is line #1</span></p> <p style="color:red"><span style="color:red">This is</span><span style="color:yellow"> line #2</span></p> <p style="color:green"><span style="color:red">This is line #3</span> <p style="color:yellow"><span style="color:yellow">This is</span><span style="color:red">line #4</span></span></p> 有行高问题,嵌套跨度会导致TinyMCE中的编辑为非,直观)
  • jQuery不可用。 Prototype.JS在父wkhtmltopdf中可用,但不在此文档中。我自己能够将jQuery代码重新格式化为纯JavaScript,但在这个实例中实际上不能使用jQuery window
  • 是的,我有现有代码。逻辑显然是如此可怕,以至于它现在不值得分享。我正在努力改进它,并且如果我能够合理地接近它就会分享它,这样它会很有用
  • 我真的知道我在做什么!我只是盯着这段代码太久了,所以正确使用的算法现在正在躲避我......

另外,我正在玩的中途完成的非功能性代码,以缓解掉票:

:-(

1 个答案:

答案 0 :(得分:6)

此解决方案在跨度上运行,展开它们(必要时),然后继续使用刚刚解开的元素,以便处理所有这些元素。左边只是文本节点子节点的顶级跨度。

function wrap(text, color) {
   var span = document.createElement("span");
   span.style.color = color;
   span.appendChild(text);
   return span;
}
function format(p) {
    for (var cur = p.firstChild; cur != null; cur = next) {
        var next = cur.nextSibling;
        if (cur.nodeType == 3) {
            // top-level text nodes are wrapped in spans
            next = p.insertBefore(wrap(cur, p.style.color), next);
        } else {
            if (cur.childNodes.length == 1 && cur.firstChild.nodeType == 3)
               continue;
            // top-level spans are unwrapped…
            while (cur.firstChild) {
                if (cur.firstChild.nodeType == 1)
                    // with nested spans becoming unnested
                    p.insertBefore(cur.firstChild, next);
                else
                    // and child text nodes becoming wrapped again
                    p.insertBefore(wrap(cur.firstChild, cur.style.color), next);
            }
            // now empty span is removed
            next = cur.nextSibling;
            p.removeChild(cur);
        }
    }
    p.style.color = p.firstChild.style.color;
}

Demo at jsfiddle.net