Как веб-приложение может обнаружить событие вставки и извлечь данные для вставки?

Я хотел бы удалить содержимое HTML, прежде чем текст будет вставлен в богатый текстовый редактор.

Очистка текста после последующей вставки работает, но проблема в том, что все предыдущее форматирование потеряно. Например, я могу написать предложение в редакторе и сделать его жирным, но когда я вставляю новый текст, все форматирование теряется. Я хочу очистить только вставленный текст и оставить любое предыдущее форматирование без изменений.

В идеале решение должно работать во всех современных браузерах (например, MSIE, Gecko, Chrome и Safari).

Обратите внимание, что в MSIE есть clipboardData.getData(), но я не смог найти аналогичные функции для других браузеров.

С момента написания этого ответа ситуация изменилась: теперь, когда Firefox добавил поддержку в версии 22, все основные браузеры теперь поддерживают доступ к данным буфера обмена в событии вставки. См. Если вы используете тег «& lt ; textarea / & gt ;», он сохранит теги html. для примера.

В прошлом это не было возможно в кросс-браузерном режиме. Идеально было бы иметь возможность получить вставленный контент с помощью paste не распространяется, если событие было привязано к фазе барботирования! , что возможно в недавних браузерах. , Эта версия

Когда вам нужно поддерживать более старые браузеры, то, что вы можете сделать, довольно сложно, и что-то вроде хака, который будет работать в браузерах Firefox 2, IE 5.5 и WebKit, таких как Safari или Chrome. Последние версии как TinyMCE, так и CKEditor используют эту технику:

  1. Обнаружить событие ctrl-v / shift-ins, используя обработчик события нажатия клавиши
  2. в форме. обработчик, сохраните текущий выбранный пользователь, добавьте закадровый элемент textarea (скажем, слева -1000px) к документу, выключите обработчик события designMode и вызовите focus() для текстовой области, таким образом перемещая курсор и эффективно перенаправляя вставку
  3. Установите очень короткий таймер (скажем, 1 миллисекунда) в обработчике событий для вызова другой функции, которая хранит значение текстовой области, удаляет текстовую область из документа, поворачивает designMode снова включен, восстанавливает выбор пользователя и вставляет текст в него.

Обратите внимание, что это будет работать только для событий вставки с клавиатуры, а не вставок из контекстного меню или меню редактирования. К тому времени, когда происходит событие вставки, уже слишком поздно перенаправлять курсор в текстовую область (по крайней мере, в некоторых браузерах).

В маловероятном случае, когда вам потребуется поддержка Firefox 2, обратите внимание, что вам нужно поместить текстовую область в родительский документ, а не документ iframe редактора WYSIWYG в этом браузере.

Решение # 1 (только для обычного текста и требуется Firefox 22)

Работает для IE6, FF 22, Chrome, Safari, Edge (только для IE9, но для более низких версии)

Если вам нужна поддержка для вставки HTML или Firefox & lt ; = 22, см. Решение # 2.

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: Не тот ответ, который вы ищете? Просмотрите другие вопросы, помеченные

… или непосредственно для объекта DOM: getData функция, которая является нестандартной. Тем не менее, он работает во всех браузерах на момент написания.


Solution # 2 (HTML и работает для Firefox & Lt ; = 22)

Протестировано в 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/

ECMAScript 6

Переменная onpaste Событие функции div имеет handlePaste присоединено к ней и передало один аргумент: event для события вставки . Особый интерес для нас представляет clipboardData JavaScript всегда имел свойства только для чтения, но вы не можете создать их самостоятельно, пока window.clipboardData, хотя у него немного другой API ,

См. Раздел ресурсов ниже.


Переменная handlepaste Как использовать:

Эта функция имеет две ветви.

, но вы можете обойти их, используя event.clipboardData и проверяет, содержит ли его свойство types ‘text / html’ (types может быть либо DOMStringList, который проверяется с помощью contains, или строку, которая проверяется с помощью indexOf метода). Если все эти условия выполнены, то мы действуем как в решении # 1, за исключением «text / html» вместо «text / plain». В настоящее время это работает в Chrome и Firefox 22.

Если этот метод не поддерживается (все другие браузеры), тогда мы

  1. сохраняем содержимое элемента в DocumentFragment
  2. Очистите элемент
  3. Вызовите waitForPastedData связывание функции

Переменная waitforpastedata Как использовать:

Эта функция сначала запрашивает вставленные данные (один раз в 20 мс), что необходимо, поскольку они не отображаются сразу. Когда данные появятся, они:

  1. Сохраняет innerHTML редактируемого div (который теперь является вставленными данными) в переменную
  2. Восстанавливает содержимое, сохраненное в DocumentFragment
  3. . Вызывает Функция ‘processPaste’ с полученными данными

Переменная processpaste Как использовать:

Произвольные вещи с вставленными данными. В этом случае мы просто предупреждаем данные, вы можете делать все что угодно. Возможно, вы захотите запустить вставленные данные через какой-то процесс очистки данных.


Сохранение и восстановление вызова позиции курсора

вернется просто Установить позицию курсора на contentEditable & Lt ; div & Gt ; ). Затем можно вставить вставленные данные в положение, в котором находился курсор, когда пользователь инициировал действие вставки.

ресурсы:

Спасибо Тиму Дауну за предложение использовать DocumentFragment и облегчить обнаружение ошибки в Firefox из-за использования DOMStringList вместо строки для clipboardData.types

Простая версия:

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

массивов clipboardData

Демо: http://jsbin.com/nozifexasu/edit?js,output

Edge, Firefox, Chrome, Safari, Opera протестированы.


Примечание: Не забудьте проверить ввод / вывод в на стороне сервера также (например, PHP-стрип-теги С чем вы столкнулись

Live Demo

Протестировано на элементе Chrome / FF / IE11

Существует раздражение в Chrome / IE, которое заключается в том, что эти браузеры добавляют <div> для каждой новой строки. Существует сообщение об этом говорится, что , и это можно исправить, установив 5) UnderscoreJs & amp ; Loadash: для метода display:inline-block

Выберите выделенный HTML-код и вставьте его здесь:

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>

Обновлен для работы с одним или несколькими URL:

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

Просто скопируйте и вставьте весь код в один HTML-файл и попробуйте вставить (используя ctrl-v) текст из буфер обмена в любом месте документа.

Я протестировал его в IE9 и новых версиях Firefox, Chrome и Opera. Работает довольно хорошо. Также хорошо, что можно использовать любой ключ Комбинация, которую он предпочитает использовать для этой функции. Конечно, не забудьте включить исходники jQuery.

Не стесняйтесь использовать этот код, и если у вас появятся какие-то улучшения или проблемы, пожалуйста, опубликуйте их обратно. Также обратите внимание, что я не являюсь Javascript разработчик, поэтому я мог что-то пропустить (= & gt ; проведите собственное тестирование).

На основании l2aelba anwser. Это было проверено на FF, Safari, Chrome, IE (8,9,10 и 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);
            }
        }
    });

Этот не использует никакого setTimeout ().

отличную статью для поддержки кросс-браузерной поддержки. this стиль Поскольку это довольно трудоемкая задача, должны быть какие-то приоритеты, если возможно

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

Этот код дополнен дескриптором выбора перед вставкой: demo

pageInit Если вам нужен уровень масштабирования сразу после сдвига, вам, вероятно, придется установить небольшой тайм-аут из-за задержки рендеринга (но я не уверен, потому что я его не тестировал). и Нам нужно БОЛЬШЕ оценить. И какой-то способ автоматически выполнить нашу функцию main (). JS:

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

. Это должно работать во всех браузерах, которые поддерживают onpaste событие и наблюдатель мутации.

Это решение выходит за рамки получения только текста, фактически позволяет редактировать вставленный контент до его вставки в элемент.

Он работает с использованием contenteditable, события onpaste (поддерживается всеми основными браузерами) и наблюдателей мутаций (поддерживается Chrome, Firefox и IE11) Расширение отдельного компонента / виджета

Улучшение содержимого страницы

Создайте HTML-элемент с contenteditable

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

По сути, они отличаются тем, как они обрабатывают аргументы функции.

Нам нужно связать pasteCallBack, так как наблюдатель мутации будет вызываться асинхронно.

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

Добавьте следующую функцию в ваш виджет кода

, чтобы увидеть некоторые реальные решения. Атрибут

можно динамически улучшить:

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

}

того, что делает код:

  1. Когда при синтаксическом анализе программы слева направо, встречается токен, который разрешен некоторым производством грамматики, но производство является
  2. В событии вставки создается новый элемент с contenteditable (элемент с contenteditable имеет повышенные привилегии) ​​
  3. Фокус установлен на новый элемент
  4. Пример улучшения:
  5. содержимое вставляется в новый элемент и отображается в DOM.
  6. Обратный вызов получает клонированный DOM. Каретка восстановлена. Вы можете изменить это, прежде чем добавить его к своей цели. элемент. В этом примере я использую функции Тима Даунса для сохранения / восстановления каретки и вставки HTML в элемент.
  7. Дом вставленного содержимого клонируется в переменную и возвращается к обратному вызову. Временный элемент уничтожен.
  8. Вот рабочий пример:

Тиму Дауну Решение, которое работает для меня, это добавление прослушивателя событий для вставки события, если вы вставляете в текстовый ввод. Так как событие вставки происходит до того, как текст в изменения ввода, внутри моего обработчика при вставке я создаю отложенную функцию, внутри которой я проверяю изменения в моем поле ввода, которые произошли при вставке: См. этот пост:

Получить вставленный контент в документе при вставке события

Еще одна вещь, вам не нужно использовать элемент ввода для создания кнопки, это можно сделать даже с помощью базового div, вот пример: поле

onPaste: function() {
    var oThis = this;
    setTimeout(function() { // Defer until onPaste() is done
        console.log('paste', oThis.input.value);
        // Manipulate pasted input
    }, 1);
}

. Это было слишком долго для комментария к ответу Нико, который, я думаю, не работает в Firefox. больше (согласно комментариям), и не работал для меня на Safari, как есть.

. Во-первых, теперь вы, кажется, умеет читать прямо из буфера обмена. Вместо кода, подобного следующему:

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

Use:

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

потому что у Firefox есть метод types и еще одним в поле DOMStringList, который не реализует test Глядя на вывод

Далее Firefox не разрешит вставку, если фокус не находится в contenteditable=true Наконец, Firefox не позволит надежно вставлять

текстовые вводы, поиск ввода & Amp ; Textareas , если только фокус не находится на я пытался скрыть текстовое поле, чтобы я мог заставить вставку работать через эмулятор JS VNC (то есть он шел к удаленному клиенту и на самом деле не было примера textarea улучшения во время события pagebeforecreate: contenteditable=true, но также:

  • не display:none
  • не visibility:hidden
  • не нулевого размера

http://jsfiddle.net/Gajotres/NwMLP/ textarea и т. Д. Для вставки в). Я обнаружил, что попытка скрыть текстовое поле в приведенном выше примере приводила к появлению симптомов, когда оно иногда срабатывало, но, как правило, не удавалось при второй вставке (или когда поле очищалось, чтобы предотвратить вставку одних и тех же данных дважды), поскольку поле теряло фокус и не восстанавливалось должным образом несмотря на focus(). Решение, которое я нашел, заключалось в том, чтобы поместить его в z-order: -1000, сделал его display:none, получится как 1px на 1px, и все цвета будут прозрачными. Тьфу.

, или если вы хотите выбрать / отменить выбор другого элемента Radiobox / Checkbox: textarea Выбрать меню display:none Глядя на вывод

Первое, что приходит на ум, — это программа-обработчик работы google по закрытию lib Чтобы проверить,

Разборный

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

, основной код: Обратите внимание: http: // jsfidd le.net/Gajotres/ck6uK/

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(/(<[wW]*?)(style)([wW]*?>)/g, function (a, b, c, d) {
        return b   'style_replace'   d;
    });
}

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

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

Теперь вы можете использовать этот плагин ;:

Простой

forEach

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

Сначала установите uid для всех существующих элементов, как атрибут данных.

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

Объяснение

Просто дайте браузеру вставить как обычно в редактируемый div содержимого, а затем после вставки поменяйте местами любые элементы span, используемые для пользовательских стилей текста, с самим текстом. Похоже, что это нормально работает в Internet Explorer и других браузерах, которые я пробовал …

Затем сравните все события POST PASTE всех узлов. Таким образом, сравнивая, вы можете идентифицировать вновь вставленный, потому что у них будет UID, а затем просто удалить стиль. Атрибут / class / id из вновь созданных элементов, чтобы вы могли сохранить прежнее форматирование.

$('#dom').on('paste',function (e){
    setTimeout(function(){
        console.log(e.currentTarget.value);
    },0);
});

контент, динамически добавляемый

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

в Panel: jQuery и {{} } Я нашел здесь много проблем, поэтому я сделал свой собственный. ни в теге включения, ни в сгенерированном теге: нет браузера, не имеющего этого по умолчанию, и поэтому он является избыточным, но также не повредит, если вы не согласны). Глядя на вывод

В случае, если мы генерируем / перестраиваем весь контент страницы, лучше всего сделать все сразу, и это можно сделать с помощью:

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;

Обновление: как указывало @RobG, выходные данные Date.prototype.toString () зависят от реализации. Поэтому используйте с осторожностью и при необходимости измените свои реализации, если вы используете это решение. В моем тестировании это надежно работает в Северной Америке, где все основные браузеры (Chrome, Safari, Firefox и IE) возвращают одинаковый формат строки.

document.onpaste = function(e) {
    var pasted = e.clipboardData.getData('Text');
    console.log(pasted)
}

На

selRange.deleteContents(); 

Смотрите полный код ниже

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