关于javascript:合并堆叠的DOM格式元素-contenteditable DIV

Consolidate stacked DOM formatting elements - contenteditable DIV

我有一个内容可编辑的DIV,该DIV已链接/同步回文本区域。

可编辑内容的DIV是一个免费的沙盒,它将在被调用时创建格式元素等。但是,这的确经常导致杂乱的堆叠元素。

我希望能够在将textarea表单发送到服务器之前清理代码。

可能会得到如下所示的结果:

1
2
3
4
5
6
7
8
9
        Hel
   
   
        l
   
 
 
   
       o World!

理想情况下将其转换为:

1
       Hello World!

如果我(递归地)遍历了div的childNode,我大概可以跟踪格式(tagName.toUpperCase() == {'B','I' ....} ) // //或执行document.queryCommandState,在此期间我可以在selectNode(thenode)上执行document.execCommand('removeFormat',false,null)

但是,我对如何跟踪格式的相邻节点有些困惑。

作为参考,这是我最近为DOM解析所做的操作,以从IMG标签中删除格式:http://jsfiddle.net/tjzGg/

NB:这是一个类似的问题> jquery-合并堆叠的DOM元素,但这是将useCSS样式行合并为一种主要样式。这是一个不同的问题,原因是我希望合并具有通用样式的文本,但由于文本的格式设置而人为地分割了多个元素。如果您使用一个内容可编辑的div并一次单独加粗一个字符,则每个元素最终将只有一个字符。


我有两种解决方案,各有其优缺点。

首先,我发现在使用gmail玩游戏时,只要格式设置样式与当前选择的模式相同,那么内容可编辑的DIV将"吸收"相邻节点。这个"免费赠品"使我只能尝试重新组织格式化的顺序,以清理大多数html汤。这不是一个完整的解决方案。理想的解决方案是具有最大的格式化模式,因为带有子集文本的父级将具有更多的嵌套模式,并且幅度逐渐减小。

在我上面的人工示例中,结果将固有地转换为:

1
2
3
4
5
        Hel
        l
     
     
....

腔室:仅使用文本进行测试,没有图像。我可以想象由于解决方案1中的节点解析和解决方案2中使用textContent.length的影响,在处理时会出现一两个错误。

解决方案1:

第一个在Chrome中有效,但是在Firefox中,调用execCommand将导致节点选择失去焦点并变为未选择状态。这是我似乎无法理解或无法解决的致命缺陷。除非我能弄清楚如何重新突出显示/选择新格式化的节点,否则此操作将被放弃。

http://jsfiddle.net/tjzGg/3/

我很希望能够与Firefox一起使用。关于我在哪里出错的任何建议。

解决方案2:

第二种方法是尝试为Firefox失去焦点提供解决方案。我能处理的唯一方法是忽略选择整个节点,而是一次选择一个字符,查看其格式,核对并按一定顺序重新应用。这在两种浏览器中均有效,但随后每个字符将DOM拆分为childNode。我不确定结合它们的最佳方法(textContent?)。

http://jsfiddle.net/LDVpD/3/

[背景:看着jsbeautifier,htmlsoup,html tidy,nokogiri,hpricot,jtidy .....我真的很惊讶,目前尚无解决方案。 GMail也会生成"丑陋"的格式!]

我知道有更好的解决方案-我很想听听一些建议。

更新

经过测试,很明显,解决方案2太慢了(通过跟踪头部来优化它并不复杂,因为它是一个渐进的"洪水",但仍然很慢),甚至一个也可以轻松实现对其进行修改以处理整个textNode,但是如果解决方案1仅在Firefox中有效,则它似乎是一种更好的方法。

解决方案1 ??2 = 3:

我发现,如果我使用格式作为切换方法,则可以正常工作,但是正如预测的那样,文本节点将基于相邻匹配格式的自然合并而增长/缩小。因此,我在睡觉时突然意识到,如果我创建了一个文本节点列表,然后从头到尾走了,那么在应用格式化时,如果内部DOM(对于Firefox !!!)正在增长/收缩,我就可以忽略不计。结合解决方案2的textNode列表(然后弹出尾节点),效果很好。实际上,迭代而不是递归文本节点(原始解决方案1方法)甚至更快。

http://jsfiddle.net/tjzGg/4/

注意:selectNodeContents与selectNode