from - JavaScript obtiene datos del portapapeles en el evento de pegado(navegador cruzado)
javascript function to copy to clipboard (20)
Solución # 1 (solo texto sin formato y requiere Firefox 22+)
Funciona para IE6 +, FF 22+, Chrome, Safari, Edge (solo probado en IE9 +, pero debería funcionar para versiones inferiores)
Si necesita soporte para pegar HTML o Firefox <= 22, consulte la Solución # 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: https://jsfiddle.net/swL8ftLs/12/
Tenga en cuenta que esta solución utiliza el parámetro ''Texto'' para la función getData
, que no es estándar. Sin embargo, funciona en todos los navegadores en el momento de la escritura.
Solución # 2 (HTML y funciona para Firefox <= 22)
Probado en 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/
Explicación
El evento onpaste
del div
tiene la función handlePaste
adjunta y pasa un solo argumento: el objeto de event
para el evento de pegar. De particular interés para nosotros es la propiedad clipboardData
de este evento que permite el acceso al portapapeles en navegadores que no son, por ejemplo. En IE, el equivalente es window.clipboardData
, aunque tiene una API ligeramente diferente.
Vea la sección de recursos a continuación.
La función del handlepaste
:
Esta función tiene dos ramas.
La primera verifica la existencia de event.clipboardData
y verifica si su propiedad de types
contiene ''text / html'' (los types
pueden ser un DOMStringList
que se verifica usando el método de los contenidos o una cadena que se verifica usando el método indexOf
). Si todas estas condiciones se cumplen, entonces procedemos como en la solución # 1, excepto con ''text / html'' en lugar de ''text / plain''. Esto funciona actualmente en Chrome y Firefox 22+.
Si este método no es compatible (todos los demás navegadores), entonces
- Guardar el contenido del elemento en un
DocumentFragment
- Vaciar el elemento
- Llame a la función
waitForPastedData
La función waitforpastedata
:
Esta función primero consulta los datos pegados (una vez cada 20 ms), lo cual es necesario porque no aparece de inmediato. Cuando los datos han aparecido:
- Guarda el innerHTML de la división editable (que ahora es el dato pegado) en una variable
- Restaura el contenido guardado en el DocumentFragment
- Llama a la función ''processPaste'' con los datos recuperados
La función de processpaste
:
Hace cosas arbitrarias con los datos pegados. En este caso solo alertamos a los datos, puedes hacer lo que quieras. Es probable que desee ejecutar los datos pegados a través de algún tipo de proceso de desinfección de datos.
Guardando y restaurando la posición del cursor
En una situación real, probablemente querría guardar la selección antes y restaurarla después ( Establecer la posición del cursor en contentEditable <div> ). Luego podría insertar los datos pegados en la posición en la que se encontraba el cursor cuando el usuario inició la acción de pegar.
Recursos:
- Evento de pegar MDN: https://developer.mozilla.org/en-US/docs/Web/Events/paste
- Portapapeles de 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
Gracias a Tim Down por sugerir el uso de DocumentFragment y abligh por detectar un error en Firefox debido al uso de DOMStringList en lugar de una cadena para clipboardData.types
¿Cómo puede una aplicación web detectar un evento de pegado y recuperar los datos que se van a pegar?
Me gustaría eliminar el contenido HTML antes de pegar el texto en un editor de texto enriquecido.
Limpiar el texto después de pegarlo después funciona, pero el problema es que se perdió todo el formato anterior. Por ejemplo, puedo escribir una oración en el editor y hacerlo en negrita, pero cuando pego un texto nuevo, se pierde todo el formato. Quiero limpiar solo el texto que se ha pegado y dejar cualquier formato anterior sin tocar.
Idealmente, la solución debería funcionar en todos los navegadores modernos (por ejemplo, MSIE, Gecko, Chrome y Safari).
Tenga en cuenta que MSIE tiene clipboardData.getData()
, pero no pude encontrar una funcionalidad similar para otros navegadores.
Basado en l2aelba anwser. Esto fue probado en FF, Safari, Chrome, IE (8,9,10 y 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);
}
}
});
Esta solución es reemplazar la etiqueta html, es simple y multiplataforma; compruebe este jsfiddle: http://jsfiddle.net/tomwan/cbp1u2cx/1/ , código del núcleo:
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, '''');
}
aviso: debe hacer un trabajo sobre el filtro xss en la parte posterior porque esta solución no puede filtrar cadenas como ''<< >>''
Este no utiliza ningún setTimeout ().
He utilizado this gran artículo para lograr la compatibilidad con varios navegadores.
$(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);
}
});
Este código se extiende con el selector de selección antes de pegar: demo
Esto debería funcionar en todos los navegadores que admiten el evento onpaste y el observador de mutación.
Esta solución va un paso más allá de solo obtener el texto, en realidad le permite editar el contenido pegado antes de que se pegue en un elemento.
Funciona mediante el uso de contenteditable, onpaste event (admitido por todos los navegadores principales) y observadores de mutación (soportados por Chrome, Firefox e IE11 +)
paso 1
Crear un elemento HTML con contenteditable
<div contenteditable="true" id="target_paste_element"></div>
paso 2
En su código Javascript agregue el siguiente evento
document.getElementById("target_paste_element").addEventListener("paste", pasteEventVerifierEditor.bind(window, pasteCallBack), false);
Necesitamos unir pasteCallBack, ya que el observador de mutación se llamará asincrónicamente.
paso 3
Agrega la siguiente función a tu código
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();
}
}
}
Lo que hace el código:
- Alguien dispara el evento de pegar usando ctrl-v, menú de contexto u otros medios
- En el evento de pegar se crea un nuevo elemento con contenteditable (un elemento con contenteditable tiene privilegios elevados)
- Se guarda la posición del cursor del elemento objetivo.
- El foco está puesto en el nuevo elemento.
- El contenido se pega en el nuevo elemento y se representa en el DOM.
- El observador de la mutación detecta esto (registra todos los cambios en el árbol de dom y el contenido). Luego dispara el evento de mutación.
- El dominio del contenido pegado se clona en una variable y se devuelve a la devolución de llamada. El elemento temporal se destruye.
- La devolución de llamada recibe el DOM clonado. El caret está restaurado. Puedes editar esto antes de agregarlo a tu objetivo. elemento. En este ejemplo, estoy usando las funciones de Tim Downs para guardar / restaurar el cursor y pegar HTML en el elemento.
Muchas gracias a Ver este post por la respuesta:
Obtener el contenido pegado en el documento en el evento de pegar
Esto fue demasiado largo para un comentario sobre la respuesta de Nico, que creo que ya no funciona en Firefox (según los comentarios), y no funcionó para mí en Safari como está.
En primer lugar, parece que ahora puedes leer directamente desde el portapapeles. En lugar de codificar como:
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'');
}
utilizar:
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'');
}
porque Firefox tiene un campo de types
que es un DOMStringList
que no implementa test
.
Next Firefox no permitirá pegar a menos que el foco esté en un campo contenteditable=true
.
Finalmente, Firefox no permitirá pegar de manera confiable a menos que el foco esté en un área de textarea
(o quizás entrada) que no solo sea contenteditable=true
sino también:
- no
display:none
- no
visibility:hidden
- no de tamaño cero
Estaba tratando de ocultar el campo de texto para poder hacer que el pegado funcionara con un emulador JS VNC (es decir, iba a un cliente remoto y no había ningún área de textarea
etc. para pegar). Encontré que tratar de ocultar el campo de texto en la parte anterior dio síntomas en los que funcionaba a veces, pero generalmente fallaba en la segunda pegada (o cuando se despejó el campo para evitar pegar los mismos datos dos veces) ya que el campo perdió el foco y no recuperaba correctamente a pesar del focus()
. La solución que se me ocurrió fue ponerlo en z-order: -1000
, display:none
, convertirlo en 1px por 1px y configurar todos los colores en transparentes. Puaj
En Safari, se aplica la segunda parte de lo anterior, es decir, debe tener un área de textarea
que no se display:none
.
Esto funcionó para mí:
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);" />
He escrito una pequeña prueba de concepto para la propuesta de Tim Downs aquí con un área de texto fuera de pantalla. Y aquí va el código:
<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>
Simplemente copie y pegue todo el código en un archivo html e intente pegar (usando ctrl-v) texto desde el portapapeles en cualquier parte del documento.
Lo he probado en IE9 y en las nuevas versiones de Firefox, Chrome y Opera. Funciona bastante bien También es bueno que se pueda usar cualquier combinación de teclas que prefiera para activar esta funcionalidad. Por supuesto no olvides incluir las fuentes de jQuery.
Siéntase libre de usar este código y si viene con algunas mejoras o problemas, por favor devuélvalos. También tenga en cuenta que no soy un desarrollador de Javascript, así que me he perdido algo (=> haga su propio testign).
La solución que funciona para mí es agregar el detector de eventos para pegar el evento si está pegando en una entrada de texto. Dado que el evento de pegado ocurre antes de que el texto en los cambios de entrada, dentro de mi controlador de pegar, creo una función diferida dentro de la cual verifico los cambios en mi cuadro de entrada que ocurrieron al pegar:
onPaste: function() {
var oThis = this;
setTimeout(function() { // Defer until onPaste() is done
console.log(''paste'', oThis.input.value);
// Manipulate pasted input
}, 1);
}
Lo primero que me viene a la mente es el pastehandler de la biblioteca de cierres de google http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html
Para limpiar el texto pegado y reemplazar el texto seleccionado actualmente con el texto pegado, el asunto es bastante trivial:
<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();
}
Puedes hacer esto de esta manera:
use este complemento de jQuery para eventos de pre y post pegado:
$.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);
});
});
};
Ahora puedes usar este plugin ;:
$(''#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();
Explicacion
Primero establece un uid para todos los elementos existentes como atributo de datos.
Luego compare todos los nodos del evento POST PASTE. Entonces, al comparar, puede identificar el nuevo insertado porque tendrá un uid, luego simplemente elimine el atributo style / class / id de los elementos recién creados, para que pueda mantener su formato anterior.
Solución simple:
document.onpaste = function(e) {
var pasted = e.clipboardData.getData(''Text'');
console.log(pasted)
}
Probado en Chrome / FF / IE11
Hay una molestia de Chrome / IE que es que estos navegadores agregan el elemento <div>
para cada nueva línea. Hay una publicación sobre esto here y se puede arreglar configurando el elemento contenteditable que se display:inline-block
Selecciona algún HTML resaltado y pégalo aquí:
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://.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>
La situación ha cambiado desde que escribí esta respuesta: ahora que Firefox ha agregado soporte en la versión 22, todos los principales navegadores ahora admiten el acceso a los datos del portapapeles en un evento de pegado. Vea la respuesta de Nico Burns para un ejemplo.
En el pasado, esto no era posible en general en un navegador cruzado. Lo ideal sería poder obtener el contenido pegado a través del evento de paste
, lo cual es posible en navegadores recientes pero no en algunos navegadores más antiguos (en particular, Firefox <22).
Cuando necesita admitir navegadores más antiguos, lo que puede hacer es bastante complicado y un poco de pirateo que funcionará en los navegadores Firefox 2+, IE 5.5+ y WebKit como Safari o Chrome. Las versiones recientes de TinyMCE y CKEditor utilizan esta técnica:
- Detecta un evento ctrl-v / shift-ins usando un controlador de eventos de pulsación de tecla
- En ese controlador, guarde la selección de usuario actual, agregue un elemento de área de texto fuera de la pantalla (por ejemplo, a la izquierda -1000px) al documento, desactive
designMode
y llame afocus()
en el área de texto, moviendo así el cursor y redireccionando efectivamente el pegado - Establezca un temporizador muy breve (digamos 1 milisegundo) en el controlador de eventos para llamar a otra función que almacene el valor del área de texto, elimine el área de texto del documento, vuelva a
designMode
, restaura la selección del usuario y pega el texto.
Tenga en cuenta que esto solo funcionará para eventos de pegado de teclado y no para pegar desde el contexto o los menús de edición. Cuando se dispara el evento de pegado, ya es demasiado tarde para redirigir el símbolo de intercalación al área de texto (al menos en algunos navegadores).
En el improbable caso de que necesite ser compatible con Firefox 2, tenga en cuenta que deberá colocar el área de texto en el documento principal en lugar del documento de marco de WYSIWYG editor en ese navegador.
Versión simple:
document.querySelector(''[contenteditable]'').addEventListener(''paste'', (e) => {
e.preventDefault();
const text = (e.originalEvent || e).clipboardData.getData(''text/plain'');
window.document.execCommand(''insertText'', false, text);
});
Utilizando clipboardData
Demostración: http://jsbin.com/nozifexasu/edit?js,output
Edge, Firefox, Chrome, Safari, Opera probado.
Nota: recuerde verificar la entrada / salida en el lado del servidor también (como las etiquetas de código PHP )
Este es un código existente publicado anteriormente, pero lo he actualizado para IE, el error se produjo cuando se selecciona el texto existente y el pegado no eliminará el contenido seleccionado. Esto ha sido corregido por el siguiente código
selRange.deleteContents();
Ver código completo a continuación
$(''[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);
}
});
Simplemente deje que el navegador pegue como de costumbre en su contenido editable div y luego, después de pegar, intercambie los elementos de separación utilizados para los estilos de texto personalizados con el texto mismo. Esto parece funcionar bien en Internet Explorer y en los otros navegadores que probé ...
$(''[contenteditable]'').on(''paste'', function (e) {
setTimeout(function () {
$(e.target).children(''span'').each(function () {
$(this).replaceWith($(this).text());
});
}, 0);
});
Esta solución asume que está ejecutando jQuery y que no desea el formato de texto en ninguno de sus divs editables de contenido .
El lado positivo es que es super simple.
$(''#dom'').on(''paste'',function (e){
setTimeout(function(){
console.log(e.currentTarget.value);
},0);
});
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;