निष्पादन में 'सादे पाठ के रूप में पेस्ट' के लिए जावास्क्रिप्ट चाल


106

मेरे पास execCommandयहां पेश किए गए नमूने के आधार पर एक मूल संपादक है। execCommandक्षेत्र के भीतर पाठ पेस्ट करने के तीन तरीके हैं:

  • Ctrl+V
  • राइट क्लिक -> पेस्ट करें
  • राइट क्लिक -> प्लेन टेक्स्ट के रूप में पेस्ट करें

मैं बिना किसी HTML मार्कअप के केवल सादे पाठ को चिपकाने की अनुमति देना चाहता हूं। मैं प्लेन टेक्स्ट को चिपकाने के लिए पहले दो कार्यों को कैसे मजबूर कर सकता हूं?

संभव समाधान: जिस तरह से मैं सोच सकता हूं कि पेस्ट से पहले ( Ctrl+ V) और एचटीएमएल टैग पट्टी के लिए कीप इवेंट के लिए श्रोता सेट करना है ।

  1. क्या यह सबसे अच्छा समाधान है?
  2. क्या पेस्ट में किसी भी HTML मार्कअप से बचना बुलेटप्रूफ है?
  3. श्रोता को राइट क्लिक में कैसे जोड़ें -> पेस्ट करें?

5
एक साइड नोट के रूप में, क्या आप संपादक में खींचे जा रहे पाठ का भी ध्यान रखना चाहते हैं? यह एक और तरीका है कि HTML संपादक में लीक हो सकता है।
pimvdb

1
@pimvdb मेरी जरूरत के लिए आप जवाब पर्याप्त थे। जिज्ञासा से बाहर, घसीटा रिसाव से बचने के लिए एक सरल विधि भी है?
Googlebot

2
मुझे लगा कि यह काम करेगा: jsfiddle.net/HBEzc/2 । लेकिन कम से कम क्रोम पर, पाठ हमेशा संपादक की शुरुआत में डाला जाता है, दुर्भाग्य से।
pimvdb

आपको यहां खोज के रूप में क्लिपबोर्ड एपी का उपयोग करने की आवश्यकता है। youtube.com/watch?v=Q81HH2Od5oo
जोहान डो

जवाबों:


247

यह pasteईवेंट को इंटरसेप्ट करेगा , रद्द करेगा pasteऔर मैन्युअल रूप से क्लिपबोर्ड का टेक्स्ट प्रतिनिधित्व सम्मिलित करेगा:
http://jsfiddle.net/HBEzN/ । यह सबसे विश्वसनीय होना चाहिए:

  • यह सभी प्रकार के चिपकाने ( 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
@ अली: मैं कुछ स्पष्ट याद किया। यदि textHTML शामिल है (जैसे यदि आप HTML कोड को सादे पाठ के रूप में कॉपी करते हैं) तो यह वास्तव में HTML के रूप में पेस्ट करेगा। यहाँ इसका हल है, लेकिन यह बहुत सुंदर नहीं है: jsfiddle.net/HBEzc/3
pimvdb

14
var text = (event.originalEvent || event).clipboardData.getData('text/plain');कुछ अधिक क्रॉस-ब्राउज़र संगतता प्रदान करता है
डंकन वॉकर

10
यह पूर्ववत कार्यक्षमता को तोड़ता है। (Ctrl + Z)
रूडी

2
महान समाधान, लेकिन यह डिफ़ॉल्ट व्यवहार से हटता है। यदि उपयोगकर्ता कुछ इस तरह <div></div>की सामग्री को कॉपी करता है, तो उसे सामग्री तत्व के एक बच्चे तत्व के रूप में जोड़ा जाएगा। मैंने इसे इस तरह तय किया:document.execCommand("insertText", false, text);
जेसन नेवेल

5
मैंने पाया insertHTMLऔर insertTextIE11 में काम नहीं करता है, हालांकि document.execCommand('paste', false, text);बस ठीक काम करता है। हालाँकि तब यह अन्य ब्राउज़र> _> में काम नहीं करता है।
जेमी बार्कर

39

मुझे IE में काम करने के लिए यहाँ स्वीकृत उत्तर नहीं मिला, इसलिए मैंने कुछ स्काउट किया और इस उत्तर पर आया जो IE11 और क्रोम और फ़ायरफ़ॉक्स के नवीनतम संस्करणों में काम करता है।

$('[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
धन्यवाद, मैं उसी मुद्दे के साथ तस्करी कर रहा था ... InsertText न तो IE11 पर काम कर रहा था और न ही नवीनतम FF :)
HeberLZ

1
क्या यह संभव है कि यह कुछ मामलों में पाठ को फ़ायरफ़ॉक्स और क्रोम दोनों में दो बार चिपकाए? मुझे लगता है ..
Fanky

1
@ फ़ैंकी मेरे पास वह मुद्दा नहीं था जब मैंने इसे बनाया था, हालाँकि मैं अब उस जगह पर काम नहीं करता जहाँ मैंने यह कोड बनाया था इसलिए मैं आपको बता नहीं सकता कि क्या यह अभी भी काम करता है! क्या आप वर्णन कर सकते हैं कि यह दो बार कैसे चिपका है?
जेमी बार्कर

2
@Fanky देखें यदि आप कर सकते हैं इसे यहाँ पर फिर से बनाने: jsfiddle.net/v2qbp829
जेमी बार्कर

2
अब लगता है कि मुझे जो समस्या थी वह आपकी स्क्रिप्ट को एक फ़ाइल से कॉल करने के कारण थी जो स्वयं एक स्क्रिप्ट द्वारा लोड की गई थी। मैं एफएफ 47.0.1 (क्रोम में कर सकते हैं) में आपके टेक्स्ट में न तो टेक्स्टरा और न ही इनपुट में पेस्ट कर सकता हूं, लेकिन डिव कंटेंटेबल में पेस्ट कर सकता हूं, जो मेरे लिए महत्वपूर्ण है। धन्यवाद!
फंकी

21

Pimvdb के रूप में एक करीबी समाधान। लेकिन यह एफएफ, क्रोम और 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');फिर आपको क्रॉस-ब्राउज़र पेस्ट / इंसर्ट कमांड के लिए केवल तर्क का उपयोग करना होगा।
गफलम

6
मुझे नहीं लगता कि आप लिख सकते हैं document.selection.createRange().pasteHTML(content)... बस IE11 पर परीक्षण किया गया है और यह उस तरह काम नहीं करता है।
विस्कॉन्सिन

3
document.execCommand('insertText', false, content)IE11 और एज के रूप में काम नहीं करता है। साथ ही, क्रोम के नवीनतम संस्करण अब समर्थन करते हैं document.execCommand('paste', false, content), जो सरल है। वे पदावनत हो सकते हैं insertText
21

19

बेशक सवाल पहले से ही उत्तर दिया गया है और विषय बहुत पुराना है, लेकिन मैं अपना समाधान प्रदान करना चाहता हूं क्योंकि यह सरल है:

यह मेरे विवादास्पद-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: अन्य एसओ पद


2
मुझे लगता है कि आप इस पोस्ट का उल्लेख कर रहे हैं: stackoverflow.com/questions/21257688/…
gfullam

1
सफारी में मेरे लिए काम नहीं कर रहा था। हो सकता है कि कुछ गलत हो
Cannicide

8

पोस्ट किए गए उत्तरों में से कोई भी वास्तव में क्रॉस ब्राउज़र काम नहीं करता है या समाधान जटिल है:

  • आदेश insertTextIE द्वारा समर्थित नहीं है
  • pasteIE11 में स्टैक ओवरफ्लो त्रुटि में कमांड परिणाम का उपयोग करना

मेरे लिए क्या काम किया (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');:। नवीनतम क्रोम, सफारी, फ़ायरफ़ॉक्स में काम करता है।
Pwdr

3

फ़ायरफ़ॉक्स आपको क्लिपबोर्ड डेटा तक पहुंचने की अनुमति नहीं देता है, इसलिए आपको इसे काम करने के लिए एक 'हैक' बनाने की आवश्यकता होगी। मैं एक पूर्ण समाधान खोजने में सक्षम नहीं हूं, हालांकि आप इसके बजाय एक textarea और पेस्ट करके 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

मैं एक सादे पाठ पेस्ट पर भी काम कर रहा था और मुझे सभी निष्पादक और गेटडेटा त्रुटियों से नफरत होने लगी थी, इसलिए मैंने इसे क्लासिक तरीके से करने का फैसला किया और यह एक आकर्षण की तरह काम करता है:

$('#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 में मेरे लिए काम करता है और अब क्रोम और सफारी में भी काम करता है। फ़ायरफ़ॉक्स में परीक्षण नहीं किया गया।


1

IE11 में, execCommand अच्छी तरह से काम नहीं करता है। मैं IE11 के लिए नीचे दिए गए कोड का उपयोग करता हूं <div class="wmd-input" id="wmd-input-md" contenteditable=true> , मेरा डिव बॉक्स है।

मैं window.clipboardData से क्लिपबोर्ड डेटा पढ़ता हूं और div के पाठ को संशोधित करता हूं और कैरेट देता हूं।

मैं कैरेट सेट करने के लिए टाइमआउट देता हूं, क्योंकि अगर मैं टाइमआउट सेट नहीं करता हूं, तो एक कैरेट 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

ठीक है जैसा कि हर कोई क्लिपबोर्ड डेटा के आसपास काम करने की कोशिश कर रहा है, कीपर ईवेंट की जाँच कर रहा है, और एक्ज़ीकॉम का उपयोग कर रहा है।

मैंने इस बारे में सोचा

कोड

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>

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.