html5 ペースト - execCommandの 'プレーンテキストとして貼り付け'のJavaScriptのトリック




改行 禁止 (9)

私は、ここで紹介したサンプルに続いてexecCommand基づく基本エディタを持っています。 execCommand領域にテキストを貼り付けるには、次の3つの方法があります。

  • Ctrl + V
  • 右クリック - >ペースト
  • 右クリック - >テキストとして貼り付け

HTMLマークアップのないプレーンテキストのみを貼り付けることができます。 最初の2つのアクションでプレーンテキストを貼り付けるにはどうすればよいですか?

可能な解決策:考えられる方法は、(Ctrl + V)のキーアップイベントのリスナーを設定し、貼り付け前にHTMLタグを取り除くことです。

  1. それは最善の解決策ですか?
  2. 貼り付けのHTMLマックアップを避けるために弾力性がありますか?
  3. 右クリック - >ペーストにリスナーを追加するには?

Answers

Internet Explorerで動作するようにここで答えを受け取ることができなかったので、私はいくつかのスカウトを行い、IE11とChromeとFirefoxの最新バージョンで動作するこの回答に来ました。

$('[contenteditable]').on('paste', function(e) {
    e.preventDefault();
    var text = '';
    if (e.clipboardData || e.originalEvent.clipboardData) {
      text = (e.originalEvent || e).clipboardData.getData('text/plain');
    } else if (window.clipboardData) {
      text = window.clipboardData.getData('Text');
    }
    if (document.queryCommandSupported('insertText')) {
      document.execCommand('insertText', false, text);
    } else {
      document.execCommand('paste', false, text);
    }
});

pasteイベントを傍受し、 pasteを取り消し、手動でクリップボードのテキスト表現を挿入します: http://jsfiddle.net/HBEzc/ : http://jsfiddle.net/HBEzc/ 。 これは最も信頼性の高いものでなければなりません:

  • すべての種類のペースト(Ctrl + V、コンテキストメニューなど)を取得します。
  • クリップボードのデータを直接テキストとして取得できるので、HTMLを置き換えるために醜いハックをする必要はありません

しかし、私はブラウザ間のサポートについてはわかりません。

editor.addEventListener("paste", function(e) {
    // cancel paste
    e.preventDefault();

    // get text representation of clipboard
    var text = e.clipboardData.getData("text/plain");

    // insert text manually
    document.execCommand("insertHTML", false, text);
});

Firefoxはクリップボードのデータにアクセスすることを許可していないので、動作させるには 'ハック'を行う必要があります。 私は完全な解決策を見つけることができませんでしたが、テキストエリアを作成して代わりに貼り付けることで、Ctrl + Vペーストを修正することができます:

//Test if browser has the clipboard object
if (!window.Clipboard)
{
    /*Create a text area element to hold your pasted text
    Textarea is a good choice as it will make anything added to it in to plain text*/           
    var paster = document.createElement("textarea");
    //Hide the textarea
    paster.style.display = "none";              
    document.body.appendChild(paster);
    //Add a new keydown event tou your editor
    editor.addEventListener("keydown", function(e){

        function handlePaste()
        {
            //Get the text from the textarea
            var pastedText = paster.value;
            //Move the cursor back to the editor
            editor.focus();
            //Check that there is a value. FF throws an error for insertHTML with an empty string
            if (pastedText !== "") document.execCommand("insertHTML", false, pastedText);
            //Reset the textarea
            paster.value = "";
        }

        if (e.which === 86 && e.ctrlKey)
        {
            //ctrl+v => paste
            //Set the focus on your textarea
            paster.focus();
            //We need to wait a bit, otherwise FF will still try to paste in the editor => settimeout
            window.setTimeout(handlePaste, 1);
        }

    }, false);
}
else //Pretty much the answer given by pimvdb above
{
    //Add listener for paster to force paste-as-plain-text
    editor.addEventListener("paste", function(e){

        //Get the plain text from the clipboard
        var plain = (!!e.clipboardData)? e.clipboardData.getData("text/plain") : window.clipboardData.getData("Text");
            //Stop default paste action
        e.preventDefault();
        //Paste plain text
        document.execCommand("insertHTML", false, plain);

    }, false);
}

私はプレーンテキストのペーストに取り組んでいました。私はexecCommandとgetDataのエラーをすべて嫌うようになったので、私はそれを古典的なやり方にすることに決めました。

$('#editor').bind('paste', function(){
    var before = document.getElementById('editor').innerHTML;
    setTimeout(function(){
        var after = document.getElementById('editor').innerHTML;
        var pos1 = -1;
        var pos2 = -1;
        for (var i=0; i<after.length; i++) {
            if (pos1 == -1 && before.substr(i, 1) != after.substr(i, 1)) pos1 = i;
            if (pos2 == -1 && before.substr(before.length-i-1, 1) != after.substr(after.length-i-1, 1)) pos2 = i;
        }
        var pasted = after.substr(pos1, after.length-pos2-pos1);
        var replace = pasted.replace(/<[^>]+>/g, '');
        var replaced = after.substr(0, pos1)+replace+after.substr(pos1+pasted.length);
        document.getElementById('editor').innerHTML = replaced;
    }, 100);
});

私の表記法を使ったコードは、ここで見つけることができます: http://www.albertmartin.de/blog/code.php/20/plain-text-paste-with-javascript : http://www.albertmartin.de/blog/code.php/20/plain-text-paste-with-javascript


function PasteString() {
    var editor = document.getElementById("TemplateSubPage");
    editor.focus();
  //  editor.select();
    document.execCommand('Paste');
}

function CopyString() {
    var input = document.getElementById("TemplateSubPage");
    input.focus();
   // input.select();
    document.execCommand('Copy');
    if (document.selection || document.textSelection) {
        document.selection.empty();
    } else if (window.getSelection) {
        window.getSelection().removeAllRanges();
    }
}

上記のコードはIE10とIE11で動作し、現在はChromeとSafariでも動作します。 Firefoxではテストされていません。


IE11では、execCommandはうまく動作しません。 私は以下のコードをIE11用に使用します。 <div class="wmd-input" id="wmd-input-md" contenteditable=true>は私のdivボックスです。

私はwindow.clipboardDataからクリップボードのデータを読み込み、divのtextContentを修正してキャレットを与えます。

私はタイムアウトを設定しなければ、キャレットはdivの終わりに行くので、キャレットを設定するためのタイムアウトを与えます。

以下の方法でIE11でclipboardDataを読んでください。 あなたがそれをしないと、改行caracterは適切に処理されないので、キャレットは間違っています。

var tempDiv = document.createElement("div");
tempDiv.textContent = window.clipboardData.getData("text");
var text = tempDiv.textContent;

IE11とクロムでテストされています。 それはIE9で動作しない可能性があります

document.getElementById("wmd-input-md").addEventListener("paste", function (e) {
    if (!e.clipboardData) {
        //For IE11
        e.preventDefault();
        e.stopPropagation();
        var tempDiv = document.createElement("div");
        tempDiv.textContent = window.clipboardData.getData("text");
        var text = tempDiv.textContent;
        var selection = document.getSelection();
        var start = selection.anchorOffset > selection.focusOffset ? selection.focusOffset : selection.anchorOffset;
        var end = selection.anchorOffset > selection.focusOffset ? selection.anchorOffset : selection.focusOffset;                    
        selection.removeAllRanges();

        setTimeout(function () {    
            $(".wmd-input").text($(".wmd-input").text().substring(0, start)
              + text
              + $(".wmd-input").text().substring(end));
            var range = document.createRange();
            range.setStart(document.getElementsByClassName("wmd-input")[0].firstChild, start + text.length);
            range.setEnd(document.getElementsByClassName("wmd-input")[0].firstChild, start + text.length);

            selection.addRange(range);
        }, 1);
    } else {                
        //For Chrome
        e.preventDefault();
        var text = e.clipboardData.getData("text");

        var selection = document.getSelection();
        var start = selection.anchorOffset > selection.focusOffset ? selection.focusOffset : selection.anchorOffset;
        var end = selection.anchorOffset > selection.focusOffset ? selection.anchorOffset : selection.focusOffset;

        $(this).text($(this).text().substring(0, start)
          + text
          + $(this).text().substring(end));

        var range = document.createRange();
        range.setStart($(this)[0].firstChild, start + text.length);
        range.setEnd($(this)[0].firstChild, start + text.length);
        selection.removeAllRanges();
        selection.addRange(range);
    }
}, false);

投稿された回答のどれも実際にクロスブラウザーで動作していないようです。解決策は複雑です。

  • コマンドinsertTextはIEではサポートされていません
  • pasteコマンドを使用すると、IE11でスタックオーバーフローエラーが発生する

何が私にとってうまくいったか(IE11、Edge、Chrome、FF)は次のとおりです:

$("div[contenteditable=true]").off('paste').on('paste', function(e) {
    e.preventDefault();
    var text = e.originalEvent.clipboardData ? e.originalEvent.clipboardData.getData('text/plain') : window.clipboardData.getData('Text');
    _insertText(text);
});

function _insertText(text) { 
    // use insertText command if supported
    if (document.queryCommandSupported('insertText')) {
        document.execCommand('insertText', false, text);
    }
    // or insert the text content at the caret's current position
    // replacing eventually selected content
    else {
        var range = document.getSelection().getRangeAt(0);
        range.deleteContents();
        var textNode = document.createTextNode(text);
        range.insertNode(textNode);
        range.selectNodeContents(textNode);
        range.collapse(false);

        var selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
    }
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<textarea name="t1"></textarea>
<div style="border: 1px solid;" contenteditable="true">Edit me!</div>
<input />
</body>

カスタムの貼り付けハンドラは、 contenteditableノードに対してのみ必要/動作することに注意してください。 ただし、 textareaとプレーンinputフィールドの両方でHTMLコンテンツを貼り付けることはサポートされていないため、ここでは何もする必要はありません。


pimvdbとしての近い解決策。 しかし、それはFF、クローム、IE 9の作業です:

editor.addEventListener("paste", function(e) {
    e.preventDefault();

    if (e.clipboardData) {
        content = (e.originalEvent || e).clipboardData.getData('text/plain');

        document.execCommand('insertText', false, content);
    }
    else if (window.clipboardData) {
        content = window.clipboardData.getData('Text');

        document.selection.createRange().pasteHTML(content);
    }   
});

JavaScriptの "strict"モードでは、ECMAScript 5が導入されています。

  (function() {
  "use strict";
   your code...
   })();

"use strict"を書く。JSファイルの一番上にある厳密な構文チェックが有効になります。それは私たちのために以下のタスクを行います:

(i)は、宣言されていない変数に代入しようとするとエラーを表示します

(ii)キーJSシステムライブラリを上書きしないようにする

(ii)安全でないか、エラーを起こしやすい言語機能を禁止する

"use strict"は個々の機能の内部でも動作します。「あなたのコードに厳密に使用する」を含めることは、常により良い方法です。

ブラウザーの互換性の問題:「使用」ディレクティブは下位互換性があります。それらをサポートしていないブラウザは、それ以上参照されない文字列リテラルが表示されます。だから、彼らはそれを越えて移動します。





javascript html5 javascript-events execcommand