1. ホーム
  2. javascript

contenteditable divのキャレットにhtmlを挿入する

2023-07-29 07:53:17

質問

contenteditableが設定されたdivがあり、エンターキーが押されたときにjqueryを使ってpreventDefault()を呼び出し、キープレスをキャプチャしています。類似の この質問 と同様に、カーソルにテキストを挿入するために、私は直接HTMLを挿入したいのですが、簡潔にするために、それをbrタグと呼ぶことにします。上記の質問に対する回答を使用すると、range.pasteHTMLメソッドを使用するため、IEで実際に動作しますが、他のブラウザではbrタグはhtmlではなくプレーンテキストとして表示されます。どうすればテキストではなくhtmlを挿入するように答えを修正できますか?

どのように解決するのですか?

ほとんどのブラウザでは insertNode() メソッドを使用して、選択範囲から取得したRangeを表示します。IE < 9では pasteHTML() を使用することができます。以下は、すべての主要なブラウザでこれを行うための関数です。コンテンツがすでに選択されている場合は置き換えられるので、これは事実上ペースト操作となります。また、挿入されたコンテンツの終わりの後にキャレットを配置するコードを追加しました。

jsFiddle http://jsfiddle.net/jwvha/1/

コードです。

function pasteHtmlAtCaret(html) {
    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();

            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = document.createElement("div");
            el.innerHTML = html;
            var frag = document.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            }
            range.insertNode(frag);

            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                range.setStartAfter(lastNode);
                range.collapse(true);
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if (document.selection && document.selection.type != "Control") {
        // IE < 9
        document.selection.createRange().pasteHTML(html);
    }
}

2013年8月21日更新

コメントで要望があったように、挿入されたコンテンツを選択するかどうかを指定する追加パラメータを持つ、更新された例を示します。

デモです。 http://jsfiddle.net/timdown/jwvha/527/

コードです。

function pasteHtmlAtCaret(html, selectPastedContent) {
    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();

            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = document.createElement("div");
            el.innerHTML = html;
            var frag = document.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            }
            var firstNode = frag.firstChild;
            range.insertNode(frag);

            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                range.setStartAfter(lastNode);
                if (selectPastedContent) {
                    range.setStartBefore(firstNode);
                } else {
                    range.collapse(true);
                }
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if ( (sel = document.selection) && sel.type != "Control") {
        // IE < 9
        var originalRange = sel.createRange();
        originalRange.collapse(true);
        sel.createRange().pasteHTML(html);
        if (selectPastedContent) {
            range = sel.createRange();
            range.setEndPoint("StartToStart", originalRange);
            range.select();
        }
    }
}