program story

execCommand에서 '일반 텍스트로 붙여 넣기'에 대한 Javascript 트릭

inputbox 2020. 8. 31. 07:44
반응형

execCommand에서 '일반 텍스트로 붙여 넣기'에 대한 Javascript 트릭


execCommand여기에 소개 된 샘플을 기반으로 한 기본 편집기가 있습니다. execCommand영역 내에 텍스트를 붙여 넣는 세 가지 방법이 있습니다.

  • Ctrl+V
  • 마우스 오른쪽 버튼 클릭-> 붙여 넣기
  • 오른쪽 클릭-> 일반 텍스트로 붙여 넣기

HTML 마크 업없이 일반 텍스트 만 붙여 넣기를 허용하고 싶습니다. 처음 두 작업을 강제로 일반 텍스트를 붙여 넣을 수 있습니까?

가능한 해결책 : 내가 생각할 수있는 방법은 ( Ctrl+ V)에 대한 keyup 이벤트에 대한 리스너를 설정 하고 붙여 넣기 전에 HTML 태그를 제거하는 것입니다.

  1. 최상의 솔루션입니까?
  2. 붙여 넣을 때 HTML 마크 업을 피하는 것이 방탄입니까?
  3. 오른쪽 클릭-> 붙여 넣기에 리스너를 추가하는 방법은 무엇입니까?

paste이벤트 를 가로 채고를 취소 paste하고 클립 보드의 텍스트 표현을 수동으로 삽입합니다 :
http://jsfiddle.net/HBEzc/ . 가장 신뢰할 수 있어야합니다.

  • 모든 종류의 붙여 넣기 ( Ctrl+ V, 컨텍스트 메뉴 등)를 포착합니다 .
  • 클립 보드 데이터를 텍스트로 직접 가져올 수 있으므로 HTML을 대체하기 위해 추악한 해킹을 할 필요가 없습니다.

그래도 브라우저 간 지원이 확실하지 않습니다.

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

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

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

IE에서 작업하기 위해 여기에서 허용되는 답변을 얻을 수 없었기 때문에 몇 가지 정찰을 수행하고 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);
    }
});

pimvdb와 같은 가까운 솔루션. 그러나 FF, Chrome 및 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);
    }   
});

물론 질문은 이미 답변되었고 주제는 매우 오래되었지만 간단하고 깨끗한 솔루션을 제공하고 싶습니다.

이것은 내 contenteditable-div의 붙여 넣기 이벤트 안에 있습니다.

var text = '';
var that = $(this);

if (e.clipboardData)
    text = e.clipboardData.getData('text/plain');
else if (window.clipboardData)
    text = window.clipboardData.getData('Text');
else if (e.originalEvent.clipboardData)
    text = $('<div></div>').text(e.originalEvent.clipboardData.getData('text'));

if (document.queryCommandSupported('insertText')) {
    document.execCommand('insertHTML', false, $(text).html());
    return false;
}
else { // IE > 7
    that.find('*').each(function () {
         $(this).addClass('within');
    });

    setTimeout(function () {
          // nochmal alle durchlaufen
          that.find('*').each(function () {
               // wenn das element keine klasse 'within' hat, dann unwrap
               // http://api.jquery.com/unwrap/
               $(this).not('.within').contents().unwrap();
          });
    }, 1);
}

다른 부분은 내가 더 이상 찾을 수없는 다른 SO- 포스트에서 가져온 것입니다 ...


업데이트 19.11.2014 : 다른 SO 포스트


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);
}

게시 된 답변 중 어떤 것도 브라우저 간 작동하지 않거나 솔루션이 너무 복잡합니다.

  • 이 명령 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>

Note that the custom paste handler is only needed/working for contenteditable nodes. As both textarea and plain input fields don't support pasting HTML content at all, so nothing needs to be done here.


I was also working on a plain text paste and I started to hate all the execCommand and getData errors, so I decided to do it the classic way and it works like a charm:

$('#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);
});

The code with my notations can be found here: 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();
    }
}

Above code works for me in IE10 and IE11 and now also works in Chrome and Safari. Not tested in Firefox.


In IE11, execCommand doesn't work well. I use below code for IE11 <div class="wmd-input" id="wmd-input-md" contenteditable=true> is my div box.

I read clipboard data from window.clipboardData and modify div's textContent and give caret.

I give timeout for setting caret, because if I don't set timeout, a caret goes to end of div.

and you should read clipboardData in IE11 in below way. If you don't do it, newline caracter is not handled properly, so caret goes wrong.

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

Tested on IE11 and chrome. It may not work on 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);

After along search and trying I have found somehow kind of optimal solution

what is important to keep in mind

// /\x0D/g return key ASCII
window.document.execCommand('insertHTML', false, text.replace('/\x0D/g', "\\n"))


and give the css style white-space: pre-line //for displaying

var contenteditable = document.querySelector('[contenteditable]')
            contenteditable.addEventListener('paste', function(e){
                let text = ''
                contenteditable.classList.remove('empty')                
                e.preventDefault()
                text = (e.originalEvent || e).clipboardData.getData('text/plain')
                e.clipboardData.setData('text/plain', '')                 
                window.document.execCommand('insertHTML', false, text.replace('/\x0D/g', "\\n"))// /\x0D/g return ASCII
        })
#input{
  width: 100%;
  height: 100px;
  border: 1px solid black;
  white-space: pre-line; 
}
<div id="input"contenteditable="true">
        <p>
        </p>
</div>   

참고URL : https://stackoverflow.com/questions/12027137/javascript-trick-for-paste-as-plain-text-in-execcommand

반응형