JavaScript get clipboard data on paste event (Cross browser)

W jaki sposób aplikacja internetowa może wykryć Zdarzenie wklejania i pobrać dane do wklejenia?

Chciałbym usunąć zawartość HTML, zanim tekst zostanie wklejony do edytora tekstu.

Czyszczenie tekstu po wklejeniu działa, ale problem polega na tym, że wszystkie poprzednie formatowanie zostaje utracone. Na przykład, mogę napisać zdanie w edytorze i uczynić je pogrubionym, ale gdy wkleję nowy tekst, całe formatowanie zostanie utracone. Chcę wyczyścić tylko tekst, który jest wklejony, i zostawić wszelkie poprzednie formatowanie nietknięte.

W idealnej sytuacji rozwiązanie powinno działać we wszystkich nowoczesnych przeglądarkach (np. MSIE, Gecko, Chrome i Safari).

Zauważ, że MSIE mA clipboardData.getData(), ale nie mogłem znaleźć podobnej funkcjonalności dla innych przeglądarek.

Author: Alex, 2010-02-01

20 answers

Sytuacja zmieniła się od czasu napisania tej odpowiedzi: Teraz, gdy Firefox dodał wsparcie w wersji 22, wszystkie główne przeglądarki obsługują teraz dostęp do danych schowka w przypadku wklejania. Zobacz odpowiedź Nico Burnsa dla przykładu.

W przeszłości nie było to ogólnie możliwe w sposób między przeglądarkowy. Idealnym rozwiązaniem byłoby uzyskanie wklejonej zawartości za pomocą zdarzenia paste, , co jest możliwe w najnowszych przeglądarkach , ale nie w niektórych starszych przeglądarkach (w szczególności, Firefox

Kiedy trzeba obsługiwać starsze przeglądarki, co można zrobić jest dość zaangażowany i trochę hack, który będzie działać w Firefox 2+, IE 5.5+ i przeglądarek WebKit, takich jak Safari lub Chrome. Najnowsze wersje zarówno TinyMCE, jak i CKEditor używają tej techniki:

  1. wykrywa Zdarzenie ctrl - v / shift-in przy użyciu obsługi zdarzenia klawiatury
  2. w tym programie obsługi Zapisz bieżący wybór użytkownika, Dodaj element textarea poza ekranem (powiedzmy po lewej-1000px) do dokumentu, obróć designMode Wyłącz i wywołaj focus() na textarea, przesuwając karetkę i skutecznie przekierowując pastę
  3. Ustawia bardzo krótki timer (powiedzmy 1 milisekundę) w programie obsługi zdarzeń, aby wywołać inną funkcję, która przechowuje wartość textarea, usuwa obszar textarea z dokumentu, włącza designMode z powrotem, przywraca wybór użytkownika i wkleja tekst.

Zauważ, że będzie to działać tylko dla zdarzeń wklejania klawiatury, a nie wklejania z menu kontekstowego lub edycji. Do czasu zdarzenia wklej jest za późno, aby przekierować karetkę do textarea(przynajmniej w niektórych przeglądarkach).

W mało prawdopodobnym przypadku, gdy musisz obsługiwać Firefoksa 2, pamiętaj, że musisz umieścić textarea w dokumencie nadrzędnym, a nie w dokumencie edytora WYSIWYG iframe w tej przeglądarce.

 133
Author: Tim Down,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:54

Rozwiązanie # 1 (tylko zwykły tekst i wymaga Firefoksa 22+)

Działa dla IE6+, FF 22+, Chrome, Safari, Edge (Testowane tylko w IE9+, ale powinny działać dla niższych wersji)

Jeśli potrzebujesz wsparcia dla wklejania HTML lub Firefox

HTML

<div id='editableDiv' contenteditable='true'>Paste</div>

JavaScript

function handlePaste (e) {
    var clipboardData, pastedData;

    // Stop data actually being pasted into div
    e.stopPropagation();
    e.preventDefault();

    // Get pasted data via clipboard API
    clipboardData = e.clipboardData || window.clipboardData;
    pastedData = clipboardData.getData('Text');

    // Do whatever with pasteddata
    alert(pastedData);
}

document.getElementById('editableDiv').addEventListener('paste', handlePaste);

JSFiddle: https://jsfiddle.net/swL8ftLs/12/

Zauważ, że to rozwiązanie wykorzystuje parametr "Text" dla funkcji getData, która jest niestandardowa. Jednak działa we wszystkich przeglądarkach w momencie pisania.


Rozwiązanie # 2 (HTML i działa dla Firefoksa [24]}testowane w IE6+, FF 3.5+, Chrome, Safari, Edge

HTML

<div id='div' contenteditable='true'>Paste</div>

JavaScript

var editableDiv = document.getElementById('editableDiv');

function handlepaste (e) {
    var types, pastedData, savedContent;

    // Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
    if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {

        // Check for 'text/html' in types list. See abligh's answer below for deatils on
        // why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as
        // Safari/Edge don't advertise HTML data even if it is available
        types = e.clipboardData.types;
        if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {

            // Extract data and pass it to callback
            pastedData = e.clipboardData.getData('text/html');
            processPaste(editableDiv, pastedData);

            // Stop the data from actually being pasted
            e.stopPropagation();
            e.preventDefault();
            return false;
        }
    }

    // Everything else: Move existing element contents to a DocumentFragment for safekeeping
    savedContent = document.createDocumentFragment();
    while(editableDiv.childNodes.length > 0) {
        savedContent.appendChild(editableDiv.childNodes[0]);
    }

    // Then wait for browser to paste content into it and cleanup
    waitForPastedData(editableDiv, savedContent);
    return true;
}

function waitForPastedData (elem, savedContent) {

    // If data has been processes by browser, process it
    if (elem.childNodes && elem.childNodes.length > 0) {

        // Retrieve pasted content via innerHTML
        // (Alternatively loop through elem.childNodes or elem.getElementsByTagName here)
        var pastedData = elem.innerHTML;

        // Restore saved content
        elem.innerHTML = "";
        elem.appendChild(savedContent);

        // Call callback
        processPaste(elem, pastedData);
    }

    // Else wait 20ms and try again
    else {
        setTimeout(function () {
            waitForPastedData(elem, savedContent)
        }, 20);
    }
}

function processPaste (elem, pastedData) {
    // Do whatever with gathered data;
    alert(pastedData);
    elem.focus();
}

// Modern browsers. Note: 3rd argument is required for Firefox <= 6
if (editableDiv.addEventListener) {
    editableDiv.addEventListener('paste', handlepaste, false);
}
// IE <= 8
else {
    editableDiv.attachEvent('onpaste', handlepaste);
}

JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/

Wyjaśnienie

Zdarzenie onpaste z div ma dołączoną funkcję handlePaste i przekazuje jeden argument: obiekt event dla zdarzenia paste. Z szczególnie interesująca jest dla nas właściwość clipboardData tego zdarzenia, która umożliwia dostęp do schowka w przeglądarkach innych niż ie. W IE odpowiednikiem jest window.clipboardData, chociaż ma nieco inne API.

Zobacz sekcję Zasoby poniżej.


Funkcja handlepaste:

Ta funkcja ma dwie gałęzie.

Pierwsze sprawdzenie istnienia event.clipboardData i sprawdzenie, czy jest to types właściwość zawiera 'text / html' (types Może Być albo DOMStringList, który jest sprawdzany za pomocą metody contains, lub łańcucha, który jest sprawdzany za pomocą metody indexOf). Jeśli wszystkie te warunki są spełnione, postępujemy tak jak w rozwiązaniu # 1, z wyjątkiem 'text / html 'zamiast' text / plain'. Obecnie działa to w Chrome i Firefox 22+.

Jeśli ta metoda nie jest obsługiwana( wszystkie inne przeglądarki), to my

  1. Zapisz zawartość elementu do DocumentFragment
  2. Opróżnij element
  3. wywołanie funkcji waitForPastedData

Na waitforpastedata funkcja:

Ta funkcja najpierw sprawdza wklejone dane (raz na 20ms), co jest konieczne, ponieważ nie pojawiają się od razu. Po pojawieniu się Danych:

  1. zapisuje innerHTML edytowalnego div (który jest teraz wklejanymi danymi) do zmiennej
  2. przywraca zawartość zapisaną w DocumentFragment
  3. wywołuje funkcję 'processPaste' z pobranymi danymi

processpaste funkcja:

Robi dowolne rzeczy z wklejonymi danymi. W tym przypadku po prostu ostrzegamy dane, możesz robić, co chcesz. Prawdopodobnie będziesz chciał uruchomić wklejone dane przez jakiś proces dezynfekcji danych.


Zapisywanie i przywracanie pozycji kursora

W prawdziwej lokalizacji prawdopodobnie chcesz zapisać zaznaczenie przed, a następnie przywrócić je ( Ustaw pozycję kursora na contentEditable

 266
Author: Nico Burns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:36

Wersja prosta:

document.querySelector('[contenteditable]').addEventListener('paste', (e) => {
    e.preventDefault();
    const text = (e.originalEvent || e).clipboardData.getData('text/plain');
    window.document.execCommand('insertText', false, text);
});

Za pomocą clipboardData

Demo : http://jsbin.com/nozifexasu/edit?js, output

testowane Edge, Firefox, Chrome, Safari, Opera.


Uwaga: pamiętaj, aby sprawdzić wejście / wyjście na Po stronie serwera również (jak PHP strip-tags)

 108
Author: l2aelba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-14 20:40:48

Live Demo

Testowane Na Chrome / FF / IE11

Istnieje problem Chrome / IE, który polega na tym, że przeglądarki te dodają element <div> do każdej nowej linii. Istnieje post o tym tutaj i można go naprawić, ustawiając contenteditable element na display:inline-block

Wybierz podświetlony HTML i wklej go tutaj:

function onPaste(e){
  var content;
  e.preventDefault();

  if( e.clipboardData ){
    content = e.clipboardData.getData('text/plain');
    document.execCommand('insertText', false, content);
    return false;
  }
  else if( window.clipboardData ){
    content = window.clipboardData.getData('Text');
    if (window.getSelection)
      window.getSelection().getRangeAt(0).insertNode( document.createTextNode(content) );
  }
}


/////// EVENT BINDING /////////
document.querySelector('[contenteditable]').addEventListener('paste', onPaste);
[contenteditable]{ 
  /* chroem bug: https://stackoverflow.com/a/24689420/104380 */
  display:inline-block;
  width: calc(100% - 40px);
  min-height:120px; 
  margin:10px;
  padding:10px;
  border:1px dashed green;
}

/* 
 mark HTML inside the "contenteditable"  
 (Shouldn't be any OFC!)'
*/
[contenteditable] *{
  background-color:red;
}
<div contenteditable></div>
 24
Author: vsync,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-21 10:13:35

Napisałem mały proof of concept dla propozycji Tim Downs tutaj z textarea poza ekranem. I oto kod:

<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> 
<script language="JavaScript">
 $(document).ready(function()
{

var ctrlDown = false;
var ctrlKey = 17, vKey = 86, cKey = 67;

$(document).keydown(function(e)
{
    if (e.keyCode == ctrlKey) ctrlDown = true;
}).keyup(function(e)
{
    if (e.keyCode == ctrlKey) ctrlDown = false;
});

$(".capture-paste").keydown(function(e)
{
    if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)){
        $("#area").css("display","block");
        $("#area").focus();         
    }
});

$(".capture-paste").keyup(function(e)
{
    if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)){                      
        $("#area").blur();
        //do your sanitation check or whatever stuff here
        $("#paste-output").text($("#area").val());
        $("#area").val("");
        $("#area").css("display","none");
    }
});

});
</script>

</head>
<body class="capture-paste">

<div id="paste-output"></div>


    <div>
    <textarea id="area" style="display: none; position: absolute; left: -99em;"></textarea>
    </div>

</body>
</html>

Wystarczy skopiować i wkleić cały kod do jednego pliku html i spróbować wkleić (za pomocą ctrl-v) tekst ze Schowka w dowolnym miejscu dokumentu.

Przetestowałem go w IE9 i nowych wersjach Firefoksa, Chrome i opery. Działa całkiem nieźle. Dobrze też, że można użyć dowolnej kombinacji klawiszy, którą preferuje, aby uruchomić tę funkcjonalność. Oczywiście nie zapomnij Dołącz źródła jQuery.

Nie krępuj się używać tego kodu, a jeśli pojawią się jakieś ulepszenia lub problemy, wyślij je z powrotem. Zauważ również, że nie jestem programistą Javascript, więc mogłem coś przeoczyć (=>Zrób swój własny testign).

 15
Author: JanM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-11 12:30:13

Na podstawie l2aelba anwser. To było testowane na FF, Safari, Chrome, IE (8,9,10 i 11)

    $("#editText").on("paste", function (e) {
        e.preventDefault();

        var text;
        var clp = (e.originalEvent || e).clipboardData;
        if (clp === undefined || clp === null) {
            text = window.clipboardData.getData("text") || "";
            if (text !== "") {
                if (window.getSelection) {
                    var newNode = document.createElement("span");
                    newNode.innerHTML = text;
                    window.getSelection().getRangeAt(0).insertNode(newNode);
                } else {
                    document.selection.createRange().pasteHTML(text);
                }
            }
        } else {
            text = clp.getData('text/plain') || "";
            if (text !== "") {
                document.execCommand('insertText', false, text);
            }
        }
    });
 10
Author: tmorell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-09 05:44:56

Ten nie używa żadnej metody setTimeout ().

Użyłem Ten świetny artykuł, aby osiągnąć obsługę wielu przeglądarek.

$(document).on("focus", "input[type=text],textarea", function (e) {
    var t = e.target;
    if (!$(t).data("EventListenerSet")) {
        //get length of field before paste
        var keyup = function () {
            $(this).data("lastLength", $(this).val().length);
        };
        $(t).data("lastLength", $(t).val().length);
        //catch paste event
        var paste = function () {
            $(this).data("paste", 1);//Opera 11.11+
        };
        //process modified data, if paste occured
        var func = function () {
            if ($(this).data("paste")) {
                alert(this.value.substr($(this).data("lastLength")));
                $(this).data("paste", 0);
                this.value = this.value.substr(0, $(this).data("lastLength"));
                $(t).data("lastLength", $(t).val().length);
            }
        };
        if (window.addEventListener) {
            t.addEventListener('keyup', keyup, false);
            t.addEventListener('paste', paste, false);
            t.addEventListener('input', func, false);
        }
        else {//IE
            t.attachEvent('onkeyup', function () {
                keyup.call(t);
            });
            t.attachEvent('onpaste', function () {
                paste.call(t);
            });
            t.attachEvent('onpropertychange', function () {
                func.call(t);
            });
        }
        $(t).data("EventListenerSet", 1);
    }
}); 

Ten kod jest rozszerzony o uchwyt wyboru przed wklejeniem: demo

 9
Author: AsgarAli Khanusiya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-07 09:05:23

Za Czyszczenie wklejonego tekstu i zastąpienie aktualnie zaznaczonego tekstu wklejonym tekstem sprawa jest dość trywialna:

<div id='div' contenteditable='true' onpaste='handlepaste(this, event)'>Paste</div>

JS:

function handlepaste(el, e) {
  document.execCommand('insertText', false, e.clipboardData.getData('text/plain'));
  e.preventDefault();
}
 5
Author: Matt Crinklaw-Vogt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-08 17:06:39

Powinno to działać na wszystkich przeglądarkach obsługujących Zdarzenie onpaste i mutation observer.

To rozwiązanie wykracza poza pobieranie tylko tekstu, w rzeczywistości pozwala edytować wklejoną zawartość, zanim zostanie wklejona do elementu.

Działa poprzez użycie contenteditable, Zdarzenie onpaste (obsługiwane przez wszystkie główne przeglądarki) en (obsługiwane przez Chrome, Firefox i IE11+)

Krok 1

Utwórz element HTML z contenteditable

<div contenteditable="true" id="target_paste_element"></div>

Krok 2

W kodzie Javascript dodaj następujące zdarzenie

document.getElementById("target_paste_element").addEventListener("paste", pasteEventVerifierEditor.bind(window, pasteCallBack), false);

Musimy powiązać pasteCallBack, ponieważ obserwator mutacji będzie wywoływany asynchronicznie.

Krok 3

Dodaj następującą funkcję do kodu

function pasteEventVerifierEditor(callback, e)
{
   //is fired on a paste event. 
    //pastes content into another contenteditable div, mutation observer observes this, content get pasted, dom tree is copied and can be referenced through call back.
    //create temp div
    //save the caret position.
    savedCaret = saveSelection(document.getElementById("target_paste_element"));

    var tempDiv = document.createElement("div");
    tempDiv.id = "id_tempDiv_paste_editor";
    //tempDiv.style.display = "none";
    document.body.appendChild(tempDiv);
    tempDiv.contentEditable = "true";

    tempDiv.focus();

    //we have to wait for the change to occur.
    //attach a mutation observer
    if (window['MutationObserver'])
    {
        //this is new functionality
        //observer is present in firefox/chrome and IE11
        // select the target node
        // create an observer instance
        tempDiv.observer = new MutationObserver(pasteMutationObserver.bind(window, callback));
        // configuration of the observer:
        var config = { attributes: false, childList: true, characterData: true, subtree: true };

        // pass in the target node, as well as the observer options
        tempDiv.observer.observe(tempDiv, config);

    }   

}



function pasteMutationObserver(callback)
{

    document.getElementById("id_tempDiv_paste_editor").observer.disconnect();
    delete document.getElementById("id_tempDiv_paste_editor").observer;

    if (callback)
    {
        //return the copied dom tree to the supplied callback.
        //copy to avoid closures.
        callback.apply(document.getElementById("id_tempDiv_paste_editor").cloneNode(true));
    }
    document.body.removeChild(document.getElementById("id_tempDiv_paste_editor"));

}

function pasteCallBack()
{
    //paste the content into the element.
    restoreSelection(document.getElementById("target_paste_element"), savedCaret);
    delete savedCaret;

    pasteHtmlAtCaret(this.innerHTML, false, true);
}   


saveSelection = function(containerEl) {
if (containerEl == document.activeElement)
{
    var range = window.getSelection().getRangeAt(0);
    var preSelectionRange = range.cloneRange();
    preSelectionRange.selectNodeContents(containerEl);
    preSelectionRange.setEnd(range.startContainer, range.startOffset);
    var start = preSelectionRange.toString().length;

    return {
        start: start,
        end: start + range.toString().length
    };
}
};

restoreSelection = function(containerEl, savedSel) {
    containerEl.focus();
    var charIndex = 0, range = document.createRange();
    range.setStart(containerEl, 0);
    range.collapse(true);
    var nodeStack = [containerEl], node, foundStart = false, stop = false;

    while (!stop && (node = nodeStack.pop())) {
        if (node.nodeType == 3) {
            var nextCharIndex = charIndex + node.length;
            if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
                range.setStart(node, savedSel.start - charIndex);
                foundStart = true;
            }
            if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
                range.setEnd(node, savedSel.end - charIndex);
                stop = true;
            }
            charIndex = nextCharIndex;
        } else {
            var i = node.childNodes.length;
            while (i--) {
                nodeStack.push(node.childNodes[i]);
            }
        }
    }

    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
}

function pasteHtmlAtCaret(html, returnInNode, selectPastedContent) {
//function written by Tim Down

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();
            if (returnInNode)
            {
                range.setStart(lastNode, 0); //this part is edited, set caret inside pasted node.
            }
            else
            {
                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();
    }
}

}

Co robi kod:

  1. ktoś uruchamia Zdarzenie paste używając ctrl-V, contextmenu lub innych środków
  2. w zdarzeniu wklej nowy element z contenteditable jest tworzony (element z contenteditable ma podwyższone uprawnienia)
  3. pozycja karetki elementu docelowego jest zapisywana.
  4. fokus jest ustawiony na nowy element
  5. zawartość jest wklejana do nowego elementu i renderowana w DOM.
  6. obserwator mutacji wychwytuje to (rejestruje wszystkie zmiany w drzewie dom i zawartości). Następnie uruchamia Zdarzenie mutacji.
  7. dom wklejonej zawartości jest klonowany do zmiennej i zwracany za oddzwonienie. Element tymczasowy zostaje zniszczony.
  8. wywołanie zwrotne odbiera sklonowany DOM. Karetka została przywrócona. Możesz to edytować przed dołączeniem do celu. element. W tym przykładzie używam funkcji Tim Downs do zapisywania / przywracania karetki i wklejania HTML do elementu.

Wielkie dzięki dla Tim Down Zobacz ten post dla odpowiedzi:

Pobierz wklejoną zawartość dokumentu podczas zdarzenia wklej

 5
Author: Mouser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:26

Rozwiązaniem, które działa dla mnie, jest dodanie słuchacza zdarzeń do wklejenia zdarzenia, jeśli wklejasz do wejścia tekstu. Ponieważ zdarzenie paste dzieje się przed tekstem w zmianach wejściowych, wewnątrz My on paste handler tworzę funkcję odroczoną, wewnątrz której sprawdzam zmiany w moim polu wprowadzania, które miały miejsce przy wklejaniu:

onPaste: function() {
    var oThis = this;
    setTimeout(function() { // Defer until onPaste() is done
        console.log('paste', oThis.input.value);
        // Manipulate pasted input
    }, 1);
}
 4
Author: Lex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-13 06:24:09

To było za długie na komentarz do odpowiedzi Nico, która chyba już nie działa na Firefoksie( wg komentarzy), a na Safari nie działa jak jest.

Po pierwsze, wydaje się, że możesz teraz czytać bezpośrednio ze schowka. Zamiast kodu jak:

if (/text\/plain/.test(e.clipboardData.types)) {
    // shouldn't this be writing to elem.value for text/plain anyway?
    elem.innerHTML = e.clipboardData.getData('text/plain');
}

Użycie:

types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/plain")) ||
    (/text\/plain/.test(types))) {
    // shouldn't this be writing to elem.value for text/plain anyway?
    elem.innerHTML = e.clipboardData.getData('text/plain');
}

Ponieważ Firefox ma pole types, które jest DOMStringList, które nie implementuje test.

Następny Firefox nie pozwoli na wklejanie, chyba że fokus jest w contenteditable=true pole.

Wreszcie Firefox nie pozwoli na wklejanie chyba, że fokus znajduje się w textarea (a może input), który jest nie tylko contenteditable=true ale także:

  • nie display:none
  • Nie visibility:hidden
  • niezerowy Rozmiar

Starałem się ukryć pole tekstowe, aby pasta działała przez emulator JS VNC(tzn. szła do zdalnego klienta i nie było właściwie textarea itp do wklejenia). Znalazłem próbując ukryć pole tekstowe w powyższym dał objawy, w których czasami działało, ale zazwyczaj nie powiodło się podczas drugiej pasty (lub gdy pole zostało wyczyszczone, aby zapobiec dwukrotnemu wklejaniu tych samych danych), ponieważ pole straciło ostrość i nie odzyskało go prawidłowo pomimo focus(). Rozwiązanie, które wymyśliłem, to umieścić go na z-order: -1000, zrobić to display:none, zrobić to jako 1px na 1px i ustawić wszystkie kolory na przezroczyste. Fuj.

Na Safari obowiązuje druga część powyższego, tzn. musisz mieć textarea, która nie jest display:none.

 4
Author: abligh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-08 07:48:44

Pierwszy, który przychodzi na myśl, to pastehandler zamknięcia Google lib http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html

 3
Author: tDo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-01 13:24:19

To mi pomogło:

function onPasteMe(currentData, maxLen) {
    // validate max length of pasted text
    var totalCharacterCount = window.clipboardData.getData('Text').length;
}

<input type="text" onPaste="return onPasteMe(this, 50);" />
 3
Author: Timmy Duncan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 17:23:26

To rozwiązanie zastępuje znacznik html, jest proste i między przeglądarkami; sprawdź to jsfiddle: http://jsfiddle.net/tomwan/cbp1u2cx/1/ , kod Rdzenia:

var $plainText = $("#plainText");
var $linkOnly = $("#linkOnly");
var $html = $("#html");

$plainText.on('paste', function (e) {
    window.setTimeout(function () {
        $plainText.html(removeAllTags(replaceStyleAttr($plainText.html())));
    }, 0);
});

$linkOnly.on('paste', function (e) {
    window.setTimeout(function () {
        $linkOnly.html(removeTagsExcludeA(replaceStyleAttr($linkOnly.html())));
    }, 0);
});

function replaceStyleAttr (str) {
    return str.replace(/(<[\w\W]*?)(style)([\w\W]*?>)/g, function (a, b, c, d) {
        return b + 'style_replace' + d;
    });
}

function removeTagsExcludeA (str) {
    return str.replace(/<\/?((?!a)(\w+))\s*[\w\W]*?>/g, '');
}

function removeAllTags (str) {
    return str.replace(/<\/?(\w+)\s*[\w\W]*?>/g, '');
}

Uwaga: powinieneś popracować nad filtrem xss z tyłu, ponieważ to rozwiązanie nie może filtrować ciągów takich jak ' > '

 2
Author: TomWan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-20 07:54:56

Możesz to zrobić w ten sposób:

Użyj tej wtyczki jQuery dla zdarzeń pre & post wklej:

$.fn.pasteEvents = function( delay ) {
    if (delay == undefined) delay = 20;
    return $(this).each(function() {
        var $el = $(this);
        $el.on("paste", function() {
            $el.trigger("prepaste");
            setTimeout(function() { $el.trigger("postpaste"); }, delay);
        });
    });
};

Teraz możesz użyć tej wtyczki;:

$('#txt').on("prepaste", function() { 

    $(this).find("*").each(function(){

        var tmp=new Date.getTime();
        $(this).data("uid",tmp);
    });


}).pasteEvents();

$('#txt').on("postpaste", function() { 


  $(this).find("*").each(function(){

     if(!$(this).data("uid")){
        $(this).removeClass();
          $(this).removeAttr("style id");
      }
    });
}).pasteEvents();

Explaination

Najpierw ustaw uid dla wszystkich istniejących elementów jako atrybut danych.

Następnie porównaj wszystkie węzły po zdarzeniu wklej. Więc porównując można zidentyfikować nowo wstawione, ponieważ będą one miały uid, a następnie po prostu usunąć atrybut style / class / id z nowo utworzonych elementów, tak, że można zachować swój starsze formatowanie.

 1
Author: Peeyush,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-18 19:26:28
$('#dom').on('paste',function (e){
    setTimeout(function(){
        console.log(e.currentTarget.value);
    },0);
});
 1
Author: Roman Yudin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 09:26:28

Po prostu pozwól przeglądarce wkleić jak zwykle w treści edytowalny div, a następnie po wklejeniu zamień dowolne elementy span używane do niestandardowych stylów tekstu z samym tekstem. Wydaje się, że działa to dobrze w Internet Explorerze i innych przeglądarkach, które próbowałem...

$('[contenteditable]').on('paste', function (e) {
    setTimeout(function () {
        $(e.target).children('span').each(function () {
            $(this).replaceWith($(this).text());
        });
    }, 0);
});

To rozwiązanie zakłada, że używasz jQuery i że nie chcesz formatować tekstu w żadnej z edytowalnych div.

Plusem jest to, że jest to bardzo proste.
 1
Author: DaveAlger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-27 01:16:54
function myFunct( e ){
    e.preventDefault();

    var pastedText = undefined;
    if( window.clipboardData && window.clipboardData.getData ){
    pastedText = window.clipboardData.getData('Text');
} 
else if( e.clipboardData && e.clipboardData.getData ){
    pastedText = e.clipboardData.getData('text/plain');
}

//work with text

}
document.onpaste = myFunct;
 1
Author: Ivan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-11 18:28:37

Proste rozwiązanie:

document.onpaste = function(e) {
    var pasted = e.clipboardData.getData('Text');
    console.log(pasted)
}
 1
Author: lama12345,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-30 08:47:55

Jest to istniejący kod opublikowany powyżej, ale zaktualizowałem go dla IE, błąd był, gdy istniejący tekst jest zaznaczony i wklejony nie usunie wybranej treści. Zostało to naprawione za pomocą poniższego kodu

selRange.deleteContents(); 

Zobacz pełny kod poniżej

$('[contenteditable]').on('paste', function (e) {
    e.preventDefault();

    if (window.clipboardData) {
        content = window.clipboardData.getData('Text');        
        if (window.getSelection) {
            var selObj = window.getSelection();
            var selRange = selObj.getRangeAt(0);
            selRange.deleteContents();                
            selRange.insertNode(document.createTextNode(content));
        }
    } else if (e.originalEvent.clipboardData) {
        content = (e.originalEvent || e).clipboardData.getData('text/plain');
        document.execCommand('insertText', false, content);
    }        
});
 0
Author: Ravi Selvaraj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-14 16:06:57