使用Javascript或jQuery清理WYSIWYG编辑器的HTML输出

时间:2014-08-04 12:58:08

标签: javascript jquery html

我使用的CMS有一个非常烦人的WYSIWYG编辑器叫做Summernote。这个编辑器看起来很漂亮,实际上工作得很好,但它输出的HTML非常糟糕,并且没有任何样式输出的配置选项。例如,这是一些带有下划线的粗体斜体文本:

<span style="text-decoration: underline;">
    <span style="font-style: italic;">
        <span style="font-weight: bold;">
            Help!! I'm being squashed by 3 heavy tags.
        </span>
    </span>
</span>

图像具有内联CSS样式,使图像具有固定的宽度,这对于响应式网站来说是无用的:

<img src="..." style="width:832px;">

YouTube iFrame的固定尺寸可以从手机屏幕上移开:

<iframe src="..." width="560" height="380">

所以,正如你所看到的,它不是很好,但我没有选择更改编辑器(不允许),我需要想出一种纠正这些问题的方法在HTML保存在数据库之前。就我而言,使用jQuery。

因此,经过一些试验和错误后,我已设法通过这个小片段修复了响应式问题:

var code = $('#summernote').code();
var newCode = $('<div></div>').append(code)
    .find('iframe').wrap('<div class="flexVideo"/>')
    .end()
    .find('img').removeAttr('style').wrap('<div class="flexPhoto"/>')
    .end()
    .html();

Working JSFIDDLE demo.

正如您所看到的,这将所有iFrame包装在响应包装器中,将所有图像包装在另一个包装器中(用于非响应目的)并从图像中删除所有内联样式,使其更加流畅。这很有效,但我在最后一部分真的很挣扎;用适当的元素替换所有这些span标签,不幸的是我需要寻求帮助。

我知道使用这样的内容可以为BOLD选择SPAN元素并使用wrapInner()unwrap()我可以用适当的文本元素替换spans:

$('span').filter(function() {
     return $(this).css('font-weight') == 'bold';
}).wrapInner('<b></b>').unwrap()

BUT

1)我甚至无法让wrapInner()使用它自己(check this fiddle)。

2)如果这实际上是可行的,无论是物理上还是效率,请咨询如何并建议如何将它们连在一起。

3)有时跨度订单会有所不同,具体取决于点击按钮的顺序。

这是我的粗制滥造,尝试失败:

var code = $('#summernote').code();
var newCode = $('<div></div>').append(code)
    .find('iframe').wrap('<div class="flexVideo"/>')
    .end()
    .find('img').removeAttr('style').wrap('<div class="flexPhoto"/>')
    .end()
    .find('span').filter(function() {
        return $(this).css('font-weight') == 'bold';
    })
    .wrapInner('<b></b>')
    .unwrap()
    .end()
    .html();

查看此失败的JSFIDDLE演示。没有任何错误,但它肯定没有按照它所说的那样做。我曾试着大喊大叫,但那不起作用。

令人惊叹的答案

对于所有受挫的Summernote用户,您可能会觉得这很有用。为什么这太棒了?好吧,虽然在这个例子中它分成了多行,但这实际上是一个单行!!

var newCode = $('<div></div>').append(code)
   .find('iframe')
       .wrap('<div class="flexVideo"/>')
   .end()
   .find('img')
       .removeAttr('style')
       .wrap('<div class="flexPhoto"/>')
   .end()
   .find('span')
       .filter("[style*='underline']")
           .removeAttr('style')
           .addClass('underline')
       .end()
       .filter("[style*='bold']")
           .wrapInner('<b></b>')
           .children()
               .unwrap()
           .end()
       .end()
       .filter("[style*='italic']")
           .wrapInner('<i></i>')
           .children()
               .unwrap()
           .end()
       .end()
   .end()
   .html();

它做了什么?

  • 从限制响应能力的图片中删除内嵌样式。
  • 在DIV中包装图像(使用按钮和文本覆盖图像的个人偏好)。
  • 在DIV中包装iframe视频以便提供响应。
  • 用类text-decoration:underline替换内联underline
  • 使用正确的<span style="font-style:italic">标记替换<i>个标记。
  • 使用正确的<span style="font-weight:bold">标记替换<b>个标记。

2 个答案:

答案 0 :(得分:2)

您的选择器都混乱,并且您没有正确引用链中所需的元素。

在这个例子中(出于诊断目的)我从末尾删除了.html()并将newCode输出到console.log()命令中,我可以在fireBug中查询。

这向我展示了过滤器选择器找不到匹配元素。我更改了过滤器以使用不同的选择器。然后我意识到你试图打开错误的元素,这正在消除你的大部分标记。所以我下降到匹配大胆跨度的孩子,然后打开它们。然后我结束了链条。

var code = '<span style="text-decoration: underline;"><span style="font-style: italic;"><span style="font-weight: bold;">asdasdad</span></span></span><br><br><img src="" style="width:748px;"><br><br><iframe src="" width="560" height="380"><iframe>';

var newCode = $('<div></div>').append(code)
    .find('iframe')
        .wrap('<div class="flexVideo"/>')
    .end()
    .find('img')
        .removeAttr('style')
        .wrap('<div class="flexPhoto"/>')
    .end()
    .find('span')
        .filter("[style*='bold']")
            .wrapInner('<strong></strong>')
            .children()
                .unwrap()
            .end()    
        .end()   
    .end()
    .html();

$('.output').text(newCode);

有关详细信息,请参阅此更新的小提琴:http://jsfiddle.net/P2Ry8/6/

答案 1 :(得分:0)

您的案例中的.unwrap()会解包span元素,而您需要解包新创建的<strong>。基本想法可以在这里看到:http://jsfiddle.net/skip405/DLuD4/

更改的html包含两个spans而不是三个。

我决定从头开始写:)

要钻进覆盖范围,我们需要检查所谓的&#34;第一级&#34;跨越并将它们更改为相应的html元素(我个人不喜欢,因为html标签具有它们的语义,对于使用wysiwyg的人来说可能不太清楚),但那是另一个讨论的话题。我还会搜索孩子spans并删除他们的style属性。

无论如何,我设法改变你的代码以获得理想的效果。你可以在这里找到:http://jsfiddle.net/skip405/DLuD4/2/

最终结果不是100%更好,但这是一个开始,希望你会发现它有用。

修改 为了让事情有点干,我修改了我的原始版本并更新了小提琴。 http://jsfiddle.net/skip405/DLuD4/4/

$('.wysiwyg').each(function(){
    var $wysiwyg = $(this),
        $directSpans = $wysiwyg.children('span');

    //first lets create top-level elements
    $directSpans.each(function(){
        var $span = $(this),
            $innerSpans = $span.find('span'),
            element = '';

        switch( $span.attr('style') ) {
            case 'font-weight: bold;':
                element = 'strong';
                break;
            case 'font-style: italic;':
                element = 'em';
                break;
            case 'text-decoration: underline;':
                element = 'u';
                break;
        }

        $span.wrapInner('<' + element + ' />').find(element).unwrap();

        $innerSpans.each(function(){
            var innerSpan = $(this),
                innerStyle = innerSpan.attr('style'),
                className = '';

            switch( innerStyle ) {
                case 'font-weight: bold;':
                    className = 'bold';
                    break;
                case 'font-style: italic;':
                    className = 'italic';
                    break;
                case 'text-decoration: underline;':
                    className = 'underline';
                    break;
            }
            innerSpan.removeAttr('style').parent().addClass(className);
        });

    });

});