JavaScript получить данные буфера обмена на событие вставки (Кросс-браузер)
как веб-приложение может обнаружить событие вставки и получить данные для вставки?
Я хотел бы удалить содержимое HTML, прежде чем текст будет вставлен в Редактор форматированного текста.
очистка текста после вставки впоследствии работает, но проблема в том, что все предыдущее форматирование теряется. Например, я могу написать предложение в редакторе и сделать его полужирным, но когда я вставляю новый текст, все форматирование теряется. Я хочу очистить только текст, который вставлен, и оставьте любое предыдущее форматирование нетронутым.
В идеале, решение должно работать во всех современных браузерах (например, MSIE, Gecko, Chrome и Safari).
обратите внимание, что MSIE имеет clipboardData.getData()
, но я не смог найти подобную функциональность для других браузеров.
20 ответов:
ситуация изменилась с момента написания этого ответа: теперь, когда Firefox добавил поддержку в версии 22, все основные браузеры теперь поддерживают доступ к данным буфера обмена в событии вставки. Смотрите ответ Нико Бернса для примера.
в прошлом это было вообще невозможно в кросс-браузере. Идеальным было бы иметь возможность получить вставленный контент через
paste
событие что возможно в последних браузерах но не в некоторых старые браузеры (в частности, Firefoxкогда вам нужно поддерживать старые браузеры, то, что вы можете сделать, довольно сложно и немного взломано, что будет работать в браузерах Firefox 2+, IE 5.5+ и WebKit, таких как Safari или Chrome. Последние версии TinyMCE и CKEditor используют этот метод:
- обнаружение события ctrl-v / shift-ins с помощью обработчика событий нажатия клавиши
- в этом обработчике сохраните текущий выбор пользователя, добавьте элемент textarea вне экрана (скажем, слева-1000px) к документу, поверните
designMode
выкл и звонокfocus()
в textarea, таким образом, перемещая курсор и эффективно перенаправляя вставить- установите очень короткий таймер (скажем, 1 миллисекунду) в обработчике событий для вызова другой функции, которая хранит значение textarea, удаляет textarea из документа, поворачивает
designMode
назад, восстанавливает выбор пользователя и вставляет текст.обратите внимание, что это будет работать только для клавиатуры пасты события, а не вставки из контекстного меню или меню редактирования. К моменту запуска события вставки слишком поздно перенаправлять курсор в текстовую область (по крайней мере, в некоторых браузерах).
в маловероятном случае, если вам нужно поддерживать Firefox 2, Обратите внимание, что вам нужно будет разместить textarea в Родительском документе, а не в документе iframe редактора WYSIWYG в этом браузере.
Решение #1 (только обычный текст и требуется Firefox 22+)
работает для IE6+, FF 22+, Chrome, Safari, Edge (Только протестировано в IE9+, но должно работать для более низких версий)
если вам нужна поддержка для вставки HTML или 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/
отметим, что это решение использует параметр "Текст" для
getData
функция, которая не является стандартной. Тем не менее, он работает во всех браузерах на момент написания статьи.
решение #2 (HTML и работает для Firefox
протестировано в 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/
объяснение
The
onpaste
событиеdiv
имеетhandlePaste
функция прикреплена к нему и передала один аргумент: the см. раздел "ресурсы" ниже.
The :
эта функция имеет два ветви.
первая проверка на наличие
event.clipboardData
и проверяет, является ли этоtypes
свойство содержит 'text / html' (types
может быть либо aDOMStringList
, которая проверяется с помощьюcontains
метод, или строка, которая проверяется с помощьюindexOf
метод). Если все эти условия выполнены, то мы действуем как в решении № 1, за исключением "text/html "вместо" text/plain". В настоящее время это работает в Chrome и Firefox 22+.если этот метод не поддерживается (все остальные браузеры), то мы
- сохранить содержимое элемента в
DocumentFragment
- пустой элемент
- вызов
waitForPastedData
функции
The
waitforpastedata
функция:эта функция сначала опрашивает вставленные данные (один раз в 20 мс), что необходимо, потому что он не появляется сразу. Когда данные появились это:
- сохраняет innerHTML редактируемого div (который теперь является вставленными данными) в переменную
- восстанавливает содержимое, сохраненное в DocumentFragment
- вызывает функцию 'processPaste' с полученными данными
The :
делает произвольные вещи с вставленными данными. В этом случае мы просто оповещаем данные, вы можете делать все, что вам нравится. Вероятно, вы захотите запустить вставленные данные через какие-то данные процесс дезинфекции.
сохранение и восстановление позиции курсора
в реальной ситуации вы, вероятно, захотите сохранить выделение раньше, а затем восстановить его ( установить положение курсора на contentEditable
). Затем вы можете вставить вставленные данные в положение, в котором находился курсор, когда пользователь инициировал действие вставки.ресурсы:
- MDN вставить событие: https://developer.mozilla.org/en-US/docs/Web/Events/paste
- буфер обмена MSDN:https://msdn.microsoft.com/en-us/library/ms535220 (v=vs.85). aspx
- MDN DocumentFragment:https://developer.mozilla.org/en/docs/Web/API/DocumentFragment
- MDN DomStringList:https://developer.mozilla.org/en/docs/Web/API/DOMStringList
спасибо Тим вниз, чтобы предложить использование DocumentFragment и abligh для перехвата ошибки в Firefox из-за использования DOMStringList вместо строки для clipboardData.типы
простой вариант:
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, выход
Edge, Firefox, Chrome, Safari, Opera протестированы.
Примечание: не забудьте проверить вход/выход на на стороне сервера также (например, PHP strip-tags)
протестировано на Chrome / FF / IE11
есть раздражение Chrome / IE, которое заключается в том, что эти браузеры добавляют
<div>
элемент для каждой новой строки. Есть пост об этом здесь и это можно исправить, установив contenteditable элемент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>
Я написал небольшое доказательство концепции для предложения Тима Даунса здесь с закадровым текстовым полем. И вот идет код:
<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, поэтому я, возможно, что-то пропустил (=>сделайте свой собственный тест).
на основе 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 ().
я использовал этой отличная статья для достижения кросс-браузерной поддержки.
$(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); } });
этот код расширяется с помощью дескриптора выбора перед вставкой: демо
на очистка вставленного текста и замена выделенного текста вставленным текстом дело довольно тривиальное:
<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 event (поддерживается всеми основными браузерами) En Mutation observers (поддерживается Chrome, Firefox и IE11+)
Шаг 1
создать HTML-элемент с contenteditable
<div contenteditable="true" id="target_paste_element"></div>
Шаг 2
в коде Javascript добавьте следующее событие
document.getElementById("target_paste_element").addEventListener("paste", pasteEventVerifierEditor.bind(window, pasteCallBack), false);
нам нужно привязать pasteCallBack, так как наблюдатель мутаций будет вызываться асинхронно.
Шаг 3
добавьте следующую функцию в ваш код
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(); } }
}
что делает этот код:
- кто-то запускает событие вставить используя ctrl-v, contextmenu или другие средства
- в событии вставки создается новый элемент с contenteditable (элемент с contenteditable имеет повышенные привилегии)
- положение курсора целевого элемента сохраняется.
- фокус установлен на новый элемент
- содержимое вставляется в новый элемент и отображается в DOM.
- наблюдатель мутаций улавливает это (он регистрирует все изменения в дереве dom и содержание.) Затем запускает событие мутации.
- dom вставленного содержимого клонируется в переменную и возвращается в обратный вызов. Временный элемент уничтожается.
- обратный вызов получает клонированный DOM. Каретка восстанавливается. Вы можете изменить это, прежде чем добавить его к вашей цели. элемент. В этом примере я использую функции Tim Downs для сохранения/восстановления курсора и вставки HTML в элемент.
большое спасибо Тим Вниз Смотрите этот пост для ответа:
получить вставленный контент на документ на вставить событие
решение, которое работает для меня, добавляет прослушиватель событий для вставки события, если вы вставляете в текстовый ввод. Поскольку событие вставки происходит до изменения текста во входных изменениях, внутри моего обработчика вставки я создаю отложенную функцию, внутри которой я проверяю изменения в своем поле ввода, которые произошли при вставке:
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'); }
использование:
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 не позволит вставить если фокус находится в
Первое, что приходит на ум-это pastehandler закрытия lib google http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html
это сработало для меня:
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);" />
Это решение заменить HTML-тег, это просто и кросс-браузер; проверьте это jsfiddle:http://jsfiddle.net/tomwan/cbp1u2cx/1/, основной код:
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, ''); }
обратите внимание: вы должны сделать некоторую работу о фильтре xss на обратной стороне, потому что это решение не может фильтровать строки, такие как '>'
Вы можете сделать это таким образом:
используйте этот плагин jQuery для событий pre & post paste:
$.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); }); }); };
теперь вы можете использовать этот плагин;:
$('#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();
объяснение
Сначала установите uid для всех существующих элементов в качестве атрибута данных.
затем сравните все узлы после вставки события. Поэтому, сравнивая, вы можете идентифицировать недавно вставленный, потому что у них будет uid, а затем просто удалите атрибут style/class/id из нового созданные элементы, так что вы можете сохранить старое форматирование.
$('#dom').on('paste',function (e){ setTimeout(function(){ console.log(e.currentTarget.value); },0); });
просто позвольте браузеру вставить как обычно в его содержимое редактируемый div, а затем после вставки поменять местами любые элементы span, используемые для пользовательских стилей текста с самим текстом. Это, кажется, работает нормально в internet explorer и других браузерах, которые я пробовал...
$('[contenteditable]').on('paste', function (e) { setTimeout(function () { $(e.target).children('span').each(function () { $(this).replaceWith($(this).text()); }); }, 0); });
Это решение предполагает, что вы используете jQuery и вы не хотите форматирования текста в любом из ваших редактируемых divs контента.
плюсом является то, что это супер простой.
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;
простое решение:
document.onpaste = function(e) { var pasted = e.clipboardData.getData('Text'); console.log(pasted) }
это существующий код, опубликованный выше, но я обновил его для IE, ошибка была, когда существующий текст выбран и вставлен, не удалит выбранный контент. Это было исправлено с помощью кода ниже
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); } });