6

我正在为新闻描述页面使用 ajax html 编辑器。当我从 word 或 internet 复制粘贴内容时,它会复制该文本、段落等的样式,这些样式克服了 html 编辑器文本框的默认类样式,我想要的是摆脱像下面这样的内联样式,而不是 html我
想把它保留在段落中吗

<span id="ContentPlaceHolder1_newsDetaildesc" class="newsDetails"><span style="font-family: arial, helvetica, sans; font-size: 11px; line-height: 14px; color: #000000; "><strong>Lorem Ipsum</strong>&nbsp;is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.<BR /> It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</span></span></p>

#left_column .newsDetails span[style] { font-family: Arial !important; font-size: small !important; font-weight: normal !important; color: #808080 !important; }

4

6 回答 6

8

首先,请注意,通过粘贴从 Word(或任何其他 HTML 源)收到的 HTML 将因源而异。即使是不同版本的 Word 也会给你完全不同的输入。如果您设计的一些代码可以完美地处理您拥有的 MS Word 版本的内容,那么它可能根本不适用于不同版本的 MS Word。

此外,一些来源会粘贴看起来像 HTML 但实际上是垃圾的内容。当您将 HTML 内容粘贴到浏览器的富文本区域时,您的浏览器与该 HTML 的生成方式无关。不要指望它在你的任何想象中都是有效的。此外,当 HTML 插入富文本区域的 DOM 时,您的浏览器会进一步处理 HTML。

因为潜在的输入变化很大,并且因为可接受的输出很难定义,所以很难为这类事情设计一个合适的过滤器。此外,您无法控制未来版本的 MS Word 将如何处理其 HTML 内容,因此您的代码将难以适应未来。

然而,振作起来!如果世界上所有的问题都是简单的问题,那将是一个非常无聊的地方。有一些潜在的解决方案。可以保留 HTML 的好的部分并丢弃不好的部分。

看起来您的基于 HTML 的 RTE 与大多数 HTML 编辑器一样工作。具体来说,它有一个 iframe,并且在 iframe 内的文档上,它已设置designMode为“on”。

paste当事件发生在<body>该 iframe 内的文档元素中时,您需要捕获该事件。我在这里非常具体,因为我必须:不要将它困在 iframe 上;不要将它困在 iframe 的窗口上;不要将它困在 iframe 的文档中。将其捕获<body>在 iframe 内的文档元素上。很重要。

var iframe = your.rich.text.editor.getIframe(), // or whatever
    win = iframe.contentWindow,
    doc = win.document,
    body = doc.body;

// Use your favorite library to attach events. Don't actually do this
// yourself. But if you did do it yourself, this is how it would be done.
if (win.addEventListener) {
    body.addEventListener('paste', handlePaste, false);
} else {
    body.attachEvent("onpaste", handlePaste);
}

请注意,我的示例代码附加了一个名为handlePaste. 我们接下来会谈到这一点。粘贴事件很有趣:有些浏览器在粘贴之前触发它,有些浏览器在粘贴之后触发它。您需要对其进行规范化,以便您始终在粘贴后处理粘贴的内容。为此,请使用超时方法。

function handlePaste() {
    window.setTimeout(filterHTML, 50);
}

因此,在粘贴事件后 50 毫秒,将调用 filterHTML 函数。这是工作的重点:您需要过滤 HTML 并删除任何不受欢迎的样式或元素。你在这里有很多事情要担心!

我个人在这些元素中看到过 MSWord 粘贴:

  1. meta
  2. link
  3. style
  4. o:p(不同命名空间中的段落)
  5. shapetype
  6. shape
  7. 评论,喜欢<!-- comment -->
  8. font
  9. 当然,还有MsoNormal课堂。

filterHTML 函数应该在适当的时候删除这些。您可能还希望删除您认为必要的其他项目。这是一个filterHTML删除我上面列出的项目的示例。

// Your favorite JavaScript library probably has these utility functions.
// Feel free to use them. I'm including them here so this example will
// be library-agnostic.
function collectionToArray(col) {
    var x, output = [];
    for (x = 0; x < col.length; x += 1) {
        output[x] = col[x];
    }
    return output;
}

// Another utility function probably covered by your favorite library.
function trimString(s) {
    return s.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}

function filterHTML() {
    var iframe = your.rich.text.editor.getIframe(),
        win = iframe.contentWindow,
        doc = win.document,
        invalidClass = /(?:^| )msonormal(?:$| )/gi,
        cursor, nodes = [];

    // This is a depth-first, pre-order search of the document's body.
    // While searching, we want to remove invalid elements and comments.
    // We also want to remove invalid classNames.
    // We also want to remove font elements, but preserve their contents.

    nodes = collectionToArray(doc.body.childNodes);
    while (nodes.length) {
        cursor = nodes.shift();
        switch (cursor.nodeName.toLowerCase()) {

        // Remove these invalid elements.
        case 'meta':
        case 'link':
        case 'style':
        case 'o:p':
        case 'shapetype':
        case 'shape':
        case '#comment':
            cursor.parentNode.removeChild(cursor);
            break;

        // Remove font elements but preserve their contents.
        case 'font':

            // Make sure we scan these child nodes too!
            nodes.unshift.apply(
                nodes,
                collectionToArray(cursor.childNodes)
            );

            while (cursor.lastChild) {
                if (cursor.nextSibling) {
                    cursor.parentNode.insertBefore(
                        cursor.lastChild,
                        cursor.nextSibling
                    );
                } else {
                    cursor.parentNode.appendChild(cursor.lastChild);
                }
            }

            break;

        default:
            if (cursor.nodeType === 1) {

                // Remove all inline styles
                cursor.removeAttribute('style');

                // OR: remove a specific inline style
                cursor.style.fontFamily = '';

                // Remove invalid class names.
                invalidClass.lastIndex = 0;
                if (
                    cursor.className &&
                        invalidClass.test(cursor.className)
                ) {

                    cursor.className = trimString(
                        cursor.className.replace(invalidClass, '')
                    );

                    if (cursor.className === '') {
                        cursor.removeAttribute('class');
                    }
                }

                // Also scan child nodes of this node.
                nodes.unshift.apply(
                    nodes,
                    collectionToArray(cursor.childNodes)
                );
            }
        }
    }
}

您包含了一些您想要过滤的示例 HTML,但您没有包含您希望看到的示例输出。如果您更新您的问题以显示您希望您的样本在过滤后的样子,我将尝试调整 filterHTML 函数以匹配。目前,请将此功能视为设计您自己的过滤器的起点。

请注意,此代码不会尝试将粘贴的内容与粘贴之前存在的内容区分开来。它不需要这样做;它删除的东西无论出现在哪里都被认为是无效的。

另一种解决方案是使用正则表达式对innerHTML文档正文过滤这些样式和内容。我已经走了这条路,我建议不要这样做,而支持我在这里提出的解决方案。您将通过粘贴收到的 HTML 会有很大差异,以至于基于正则表达式的解析将很快遇到严重问题。


编辑:

我想我现在明白了:您正在尝试自己删除内联样式属性,对吗?如果是这样,您可以在 filterHTML 函数中通过包含以下行来执行此操作:

cursor.removeAttribute('style');

或者,您可以针对特定的内联样式进行删除,如下所示:

cursor.style.fontFamily = '';

我更新了 filterHTML 函数来显示这些行的去向。

祝你好运,编码愉快!

于 2011-05-31T14:31:00.890 回答
4

这是一个从 HTML 中去除文本的潜在解决方案。它首先将文本作为 HTML 复制到一个元素中(可能应该隐藏,但在我的示例中显示为比较)。接下来,您将获得该元素的 innerText。然后,您可以将该文本放入您喜欢的任何位置的编辑器中。您必须在编辑器上捕获粘贴事件,运行此序列以获取文本,然后将该文本放在您喜欢的编辑器中的任何位置。

这是一个如何做到这一点的例子的小提琴:Getting text from HTML

于 2011-05-27T21:44:53.663 回答
2

如果您使用的是 Firefox,则可以安装此扩展程序:https ://addons.mozilla.org/en-US/firefox/addon/extended-copy-menu-fix-vers/ 。它允许您从任何网站复制文本而无需格式化。

于 2011-05-27T21:06:56.350 回答
2

通常,当最终用户支持 HTML 编辑时,我选择利用许多可靠的客户端 HTML 编辑控件之一,这些控件已经内置了处理此类内容的必要功能。有许多商业版本,例如来自Component Art,以及一些很棒的免费/开源版本,例如CKEditor

所有好的都支持从 Word 中粘贴来去除/修复过多的 CSS。我要么只利用一个(简单的方法),要么看看他们是如何做到的(困难的)。

于 2011-05-29T02:16:22.503 回答
1

我总是遇到这种问题,这很有趣。好吧,我的做法很简单,只需在 Windows 中打开记事本,然后将文本粘贴到记事本中,然后复制到 AJAX 文本编辑器即可。它将剥离您所有的文本样式。

:)

于 2011-06-03T09:09:22.690 回答
1

根据我从您的问题中了解到的情况,您使用的是所见即所得的编辑器。当从其他网页或 word 文档中复制和粘贴文本时,您会得到一些带有内联样式等的丑陋 html。

我建议您根本不要费心解决这个问题,因为跨浏览器处理这个问题很麻烦。如果你真的想修复它,我会推荐使用 TinyMCE,它可以得到你想要的这种确切行为。

您可以通过访问http://tinymce.moxiecode.com/tryit/full.php来尝试它,只需将一些文本复制到编辑器中,然后将其全部提交以查看生成的 html。它很干净。

TinyMCE 可能是 imo 中最好的 WYSIWYG 编辑器。因此,与其自己构建东西,不如使用它并根据您的确切需求对其进行定制。

于 2011-06-03T09:13:55.470 回答