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


106

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

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

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

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

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

5
참고로 편집기로 드래그되는 텍스트도 처리 하시겠습니까? 이것은 HTML이 편집기로 유출 될 수있는 또 다른 방법입니다.
pimvdb

1
@pimvdb 당신의 대답은 내 필요에 충분했습니다. 호기심에서 끌린 누출을 피할 수있는 간단한 방법이 있습니까?
Googlebot

2
나는 이것이 일을 할 것이라고 생각했다 : jsfiddle.net/HBEzc/2 . 그러나 적어도 Chrome에서는 텍스트가 항상 편집기 시작 부분에 삽입됩니다.
pimvdb

여기에서 설명하기 위해 클립 보드 API를 사용해야합니다. youtube.com/watch?v=Q81HH2Od5oo
Johne Doe

답변:


247

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

4
@Ali : 나는 명백한 것을 놓쳤다. textHTML 이 포함 된 경우 (예 : HTML 코드를 일반 텍스트로 복사하는 경우) 실제로 HTML로 붙여 넣습니다. 여기에 해결책이 있지만 그다지 예쁘지는 않습니다 : jsfiddle.net/HBEzc/3 .
pimvdb

14
var text = (event.originalEvent || event).clipboardData.getData('text/plain');브라우저 간 호환성 향상
Duncan Walker

10
이로 인해 실행 취소 기능이 중단됩니다. (Ctrl + Z)
Rudey

2
훌륭한 솔루션이지만 이것은 기본 동작과 다릅니다. 사용자가 <div></div>해당 콘텐츠를 복사 하면 contenteditable 요소의 자식 요소로 추가됩니다. 나는 이런 식으로 고정 :document.execCommand("insertText", false, text);
제이슨 뉴웰

5
나는 발견 insertHTML하고 insertText그러나, IE11에서 일을하지 않는 document.execCommand('paste', false, text);잘 작동합니다. 다른 브라우저에서는 작동하지 않는 것 같지만> _>.
Jamie Barker

39

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

1
내가 같은 문제를 truggling되었다 주셔서 감사합니다 ...있는 InsertText는 : IE11도 최신 FF도에 작동하지 않는
HeberLZ

1
경우에 따라 Firefox와 Chrome에서 텍스트를 두 번 붙여 넣을 수 있습니까? 나에게 보인다 ..
Fanky

1
@Fanky 나는 그것을 만들 때 그 문제가 없었지만 더 이상이 코드를 만든 곳에서 일하지 않으므로 여전히 작동하는지 말할 수 없습니다! 두 번 붙여 넣는 방법을 설명해 주시겠습니까?
Jamie Barker

2
@Fanky 여기에서 다시 만들 수 있는지 확인하십시오 : jsfiddle.net/v2qbp829 .
Jamie Barker

2
내가 가진 문제는 스크립트에 의해 자체적으로로드 된 파일에서 스크립트를 호출했기 때문인 것 같습니다. FF 47.0.1 (크롬에서 할 수 있음)의 바이올린에 텍스트 영역이나 입력에 붙여 넣을 수는 없지만 div contenteditable에 붙여 넣을 수 있습니다. 감사!
Fanky

21

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

5
나는 단락 content변수 할당을 좋아합니다 . getData('Text')브라우저 간 작업 을 사용하여 var content = ((e.originalEvent || e).clipboardData || window.clipboardData).getData('Text');다음 과 같이 한 번만 할당 할 수 있음을 발견했습니다 . 그러면 브라우저 간 붙여 넣기 / 삽입 명령에 논리를 사용해야합니다.
gfullam 2014

6
나는 당신이 쓸 수 있다고 생각하지 않습니다 document.selection.createRange().pasteHTML(content)... IE11에서 테스트했으며 그렇게 작동하지 않습니다.
vsync 2015

3
document.execCommand('insertText', false, content)IE11 및 Edge에서는 작동하지 않습니다. 또한 최신 버전의 Chrome은 이제 document.execCommand('paste', false, content)더 간단한를 지원 합니다. 더 이상 사용되지 않을 수 있습니다 insertText.
Cannicide

19

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

이것은 내 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 포스트


2
나는 당신이이 포스트를 언급하고 있다고 생각한다 : stackoverflow.com/questions/21257688/…
gfullam

1
Safari에서 나를 위해 작동하지 않는 것 같습니다. 뭔가 잘못되었을 수 있습니다
Cannicide

8

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

  • 이 명령 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 콘텐츠 붙여 넣기를 전혀 지원하지 않으므로 여기에서 아무것도 수행 할 필요가 없습니다.


.originalEvent이 작업을 수행하려면 이벤트 처리기 (3 행)에서 제거 해야했습니다. 따라서 전체 라인은 다음과 같습니다 const text = ev.clipboardData ? ev.clipboardData.getData('text/plain') : window.clipboardData.getData('Text');.. 최신 Chrome, Safari, Firefox에서 작동합니다.
Pwdr

3

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

2

또한 일반 텍스트 붙여 넣기 작업을하고 있었고 모든 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 에서 찾을 수 있습니다 .


1
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에서 테스트되지 않았습니다.


1

IE11에서는 execCommand가 제대로 작동하지 않습니다. IE11 <div class="wmd-input" id="wmd-input-md" contenteditable=true> 에 대한 아래 코드 는 내 div 상자입니다.

window.clipboardData에서 클립 보드 데이터를 읽고 div의 textContent를 수정하고 캐럿을 제공합니다.

타임 아웃을 설정하지 않으면 캐럿이 div의 끝으로 이동하기 때문에 캐럿 설정에 대한 타임 아웃을 제공합니다.

IE11에서 다음과 같이 클립 보드 데이터를 읽어야합니다. 하지 않으면 개행 문자가 제대로 처리되지 않아 캐럿이 잘못됩니다.

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

0

검색하고 시도한 후 어떻게 든 최적의 솔루션을 찾았습니다.

명심해야 할 중요한 사항

// /\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>   


0

모두가 클립 보드 데이터를 다루고, 키 누르기 이벤트를 확인하고, execCommand를 사용하고 있으므로 좋습니다.

나는 이것을 생각했다

암호

handlePastEvent=()=>{
    document.querySelector("#new-task-content-1").addEventListener("paste",function(e)
    {
        
        setTimeout(function(){
            document.querySelector("#new-task-content-1").innerHTML=document.querySelector("#new-task-content-1").innerText.trim();
        },1);
    });

}
handlePastEvent();
<div contenteditable="true" id="new-task-content-1">You cann't paste HTML here</div>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.