Pegar en contentedittable da como resultado la inserción aleatoria de etiquetas

Estoy usando un campo contentedittable como entrada de usuario para poder aprovechar el formato de texto. Desafortunadamente, he descubierto que cuando un usuario pega en el campo una gran cantidad de html desagradable viene con él. Solo quiero el texto sin formato del portapapeles.

¡¿Por qué está pasando esto?!

Un ejemplo truncado:

<div><br></div><div><span class="Apple-style-span" style="font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 13px; line-height: 12px; color: rgb(0, 0, 0); "><table style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; border-collapse: collapse; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; background-position: initial initial; background-repeat: initial initial; "><tbody style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; "><tr style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; "><td class="votecell" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: top; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; width: 60px; background-position: initial initial; background-repeat: initial initial; "><div class="vote" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; text-align: center; background-position: initial initial; background-repeat: initial initial; "><span class="vote-count-post" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 31px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; display: block; color: rgb(128, 129, 133); font-weight: bold; background-position: initial initial; background-repeat: initial initial; ">1</span><a class="vote-down-off" title="This question does not show any research effort; it is unclear or not useful (click again to undo)" style="margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 1px; vertical-align: baseline; background-image: url(http://sstatic.net/stackoverflow/img/sprites.png?v=3); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: rgb(0, 119, 204); text-decoration: none; cursor: pointer; overflow-x: hidden; overflow-y: hidden; display: block; width: 41px; height: 25px; text-indent: -9999em; background-position: 0px -300px; background-repeat: no-repeat no-repeat; ">...

preguntado el 16 de mayo de 11 a las 19:05

2 Respuestas

Solo puede obtener el texto sin formato usando un truco. Las versiones recientes de TinyMCE y CKEditor utilizan esta técnica en sus editores basados ​​en iframe:

  1. Detectar un Ctrl-v / cambio-recuadro evento usando un controlador de eventos de pulsación de tecla
  2. En ese controlador, guarde la selección de usuario actual, agregue un elemento de área de texto fuera de la pantalla (digamos a la izquierda -1000px) al documento, gire contentEditable apagar y llamar focus() en el área de texto, moviendo así el cursor y redirigiendo efectivamente la pasta
  3. Establezca un temporizador muy breve (digamos 1 milisegundo) en el controlador de eventos para llamar a otra función que almacena el valor del área de texto, elimina el área de texto del documento, gira contentEditable vuelve a encender, 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 pegados desde el contexto o los menús de edición. La paste event sería mejor, pero para cuando se activa, es demasiado tarde para redirigir el cursor al área de texto en la mayoría de los navegadores.

contestado el 17 de mayo de 11 a las 01:05

Hmmmm suena un poco complicado y necesito adaptarme a los usuarios que hacen clic derecho en pegar. ¿Quizás un reemplazo de expresiones regulares para etiquetas no válidas? - wilsonpage

@pagewil: Si fuera usted, evitaría usar expresiones regulares para analizar HTML. Otra opción es abrir un cuadro de diálogo que contenga un área de texto cuando el usuario lo pegue cuando el paste incendios de eventos. - Tim Down

¿Por qué no se recomienda la expresión regular? - wilsonpage

@pagewil: si bien es posible tratar con un conjunto estrictamente limitado de cadenas HTML con expresiones regulares, en general no es posible analizar HTML con expresiones regulares de JavaScript, y con contenido pegado desde fuentes externas, el HTML podría ser cualquier cosa. Aquí hay un par de enlaces sobre el tema: stackoverflow.com/questions/590747/… y el clásico stackoverflow.com/questions/1732348/… - Tim Down

Estás recibiendo todas esas tonterías adicionales porque un contenteditable elemento soporta el text/html Tipo de Mimica. Cuando pegas algo del portapapeles, a menudo hay una fase de negociación de contenido:

  • El destino de pegado dice "Admito estos tipos de contenido: ..."
  • El administrador del portapapeles luego analiza esa lista con la fuente de datos para obtener los datos pegados en un formato adecuado para el destino de pegado.
  • Y finalmente, los datos se descargan en su contenteditable elemento como text/html con todo ese ruido extra.

Es posible que el proceso no sea exactamente como el anterior, pero será similar. Su mejor apuesta probablemente sería agregar un controlador para el paste evento y use ese controlador para convertir los datos pegados a text/plain.

contestado el 17 de mayo de 11 a las 00:05

¿Puede sugerir la mejor manera de orientar solo los datos pegados? No quiero quitar las etiquetas html del texto que ya puede estar en el campo. - wilsonpage

@pagewil: Eche un vistazo al enfoque de Tim Down. También puede tomar TinyMCE o CKEditor y ver cómo manejan pegar a través del menú. Yo no administro el mío contenteditable elementos, siempre he usado uno de los editores existentes para ese tipo de cosas. - mu es demasiado corto

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.