まず、Word(またはその他のHTMLソース)から貼り付けることで受け取るHTMLは、ソースによって大きく異なることに注意してください。Wordのバージョンが異なっていても、入力は根本的に異なります。使用しているバージョンのMSWordのコンテンツで完全に機能するコードを設計した場合、別のバージョンのMSWordではまったく機能しない可能性があります。
また、一部のソースはHTMLのように見えるが、実際にはゴミであるコンテンツを貼り付けます。HTMLコンテンツをブラウザのリッチテキスト領域に貼り付ける場合、ブラウザはそのHTMLの生成方法とは何の関係もありません。あなたの想像力の範囲によってそれが有効であると期待しないでください。さらに、ブラウザは、リッチテキスト領域のDOMに挿入されるHTMLをさらに変更します。
潜在的な入力は非常に変化し、許容可能な出力を定義するのは難しいため、この種のものに適切なフィルターを設計することは困難です。さらに、MS Wordの将来のバージョンがHTMLコンテンツを処理する方法を制御できないため、コードの将来性を保証することは困難です。
しかし、心を持ってください!世界の問題がすべて簡単なものだとしたら、それはかなり退屈な場所になるでしょう。いくつかの潜在的な解決策があります。HTMLの良い部分を保持し、悪い部分を破棄することが可能です。
HTMLベースのRTEは、ほとんどのHTMLエディタと同じように機能するようです。具体的には、iframeがあり、iframe内のドキュメントではdesignMode
「オン」に設定されています。
そのiframe内のドキュメントpaste
の要素で発生したイベントをトラップする必要があります。<body>
私はここで非常に具体的である必要があります。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の貼り付けを見てきました:
meta
link
style
o:p
(別の名前空間の段落)
shapetype
shape
- のようなコメント
<!-- comment -->
。
font
- そしてもちろん、
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関数を更新して、これらの行がどこに行くかを示しました。
幸運と幸せなコーディング!