En Discourse, si pegas texto sin formato en el editor, el comportamiento típico del navegador con Ctrl+Z deshace ese pegado y elimina el texto pegado. Sin embargo, si pegas texto con formato como este texto en negrita, deshacer no funciona. De manera similar, pegar enlaces sobre texto para enlazarlos no se puede deshacer, ni tampoco el markdown insertado mediante atajos como Ctrl+B o al añadir formato desde las opciones de la barra de herramientas del editor. Idealmente, la mayor parte de esto se añadiría a la pila de deshacer para que Ctrl+Z funcione.
Permítanme describir lo que me sucede con bastante frecuencia.
Copio texto de otro sitio web que resulta ser un enlace, negrita, un encabezado, etc. (A veces este hecho se registra y a veces no).
Voy a Discourse para pegar este texto en mi publicación, que ya está parcialmente escrita.
Presiono Ctrl+V, lo que inserta el texto con formato.
Me doy cuenta de mi error y presiono Ctrl+Z, lo que no hace nada.
Elimino manualmente el texto con formato que inserté por error. (La mayoría de las veces es la versión enlazada que pegué por error, así que no es como si solo tuviera que eliminar un # o algo así).
Presiono Ctrl+Shift+V, lo que debería haber hecho la primera vez para pegar el texto sin formato.
Obviamente, esto es en parte un error del usuario, y cuando no me equivoco, solo son dos pasos (copiar de otro sitio web, pegar como texto sin formato en Discourse). Pero cuando me equivoco (lo que sucede a menudo ya que estoy acostumbrado a presionar Ctrl+V dado que la mayoría de los sitios web no pegan con formato), sería bueno si pudiera ahorrar algo de tiempo haciendo que Ctrl+Z funcione como de costumbre.
Este es generalmente un comportamiento nativo del navegador y no algo que Discourse esté haciendo. Intenta probarlo en un cuadro de texto plano en HTML.
De acuerdo, la opción de deshacer no funciona por defecto cuando se utiliza JavaScript para modificar una entrada. Pero busqué en Google y descubrí que document.execCommand puede insertar texto y añadirlo a la pila de deshacer.
Por ejemplo, si haces document.getElementById('myInput').value = 'asd' y luego Ctrl+Z, no se deshará.
Pero si haces document.execCommand('insertText', false, 'asd') mientras el cursor está donde quieres (que debería ser así según el flujo de trabajo actual de Discourse), el texto se inserta correctamente y Ctrl+Z eliminará el texto añadido como se espera.
Básicamente, me pregunto si document.execCommand (o algún otro proceso si se considera mejor otro enfoque) se puede utilizar para añadir a la pila de deshacer para que Ctrl+Z funcione en estos casos.
No; retiramos intencionadamente esa compatibilidad de Discourse hace años, en favor de dejar que el manejo nativo de deshacer del cuadro de texto del navegador funcione como debe en todos los sitios web estándar.
Creo que me estoy perdiendo algo. ¿Qué significa exactamente “dejar que el manejo de deshacer de la caja de texto nativa del navegador funcione”? Por lo que puedo decir, el deshacer para texto con formato no funciona en absoluto en Discourse, así que ¿estás diciendo que el hecho de que el deshacer no funcione es el comportamiento estándar del sitio web?
La razón por la que estoy confundido es porque no se me ocurre ningún sitio web (aparte de cosas como Microsoft Word donde funciona el deshacer) que admita el pegado con formato además de Discourse. Así que no tengo nada con qué comparar Discourse para ver qué es “estándar”. Si pudieras señalarme algunos sitios web para comparar, sería de gran ayuda.
Presiona Pruébalo tú mismo, luego ingresa texto en el cuadro de texto, haz una pausa y presiona Ctrl+Z para deshacer tus acciones. Aquí tienes una demostración. Primero presionamos el botón Pruébalo tú mismo, lo que da como resultado que se muestre un textarea HTML en el navegador.
Ten en cuenta que el texto ha vuelto a su estado anterior, y esto fue manejado al 100% por el propio navegador, sin involucrar ningún código JavaScript.
Mi entendimiento es que @seanblue está preguntando si podemos modificar las APIs del navegador que usamos cuando manipulamos el textarea para dar mejores indicaciones al navegador para que pueda manejar mejor el undo. Por lo tanto, esto solo se aplicaría a los atajos de teclado, y a la barra de herramientas, carga y cosas así.
No estoy en contra de ajustar cosas aquí, pero me preocupa que algunas de estas APIs requieran mucho cuidado, ciertamente existe el riesgo de regresiones.
No estoy en contra de los experimentos aquí, tal vez si la comunidad desea enviar algunas PRs para mostrarnos cómo se hace.
Podríamos hacerlo mucho mejor aquí. Muchos de nuestros botones de barra de herramientas y el comportamiento de pegado especial establecen directamente el valor del textarea en JavaScript. Esto rompe totalmente el historial nativo de deshacer/rehacer del navegador.
En su lugar, cada vez que realicemos modificaciones programáticas en el textarea, deberíamos usar document.execCommand (como mencionó @seanblue). De esa manera, el navegador lo interpreta igual que una acción del usuario y lo inserta limpiamente en el historial de deshacer/rehacer.
el comando insertText, que puedes usar para reemplazar programáticamente texto en el cursor preservando el búfer de deshacer (historial de edición) en elementos textarea y input simples.
Pero ese cuadro de texto no maneja texto con formato, que no es de lo que estoy hablando. Sé que los navegadores manejan el deshacer del texto escrito y pegado normalmente. Mi punto es que Discourse no maneja el deshacer del texto con formato pegado. Sigue estos pasos para ver de lo que estoy hablando.
Ahora copia el siguiente texto en su lugar y pégalo en el compositor: esto es una prueba genial
Observa que lo pega con el markdown para poner en cursiva “genial”.
Así es. No sugiero manejar el deshacer tú mismo en JavaScript. Sugiero que cuando manipules el área de texto, se lo hagas saber al navegador para que pueda deshacer el cambio por sí mismo cuando el usuario presione Ctrl+Z.
Por lo que vale, el 99% de mi frustración se resolvería si Ctrl+Z funcionara después de pegar texto con formato. ¿Sería ideal si cada operación pudiera deshacerse con Ctrl+Z? Claro. Pero la mayoría de las otras operaciones se pueden deshacer repitiendo la operación original (por ejemplo, hacer Ctrl+B puede agregar y quitar el markdown en negrita). Pero con el pegado, tiene el potencial de incluir una cantidad significativa de markdown inesperado, incluidos encabezados, enlaces e incluso tablas, por lo que es tan importante que el deshacer funcione en ese caso.
Si redujéramos el alcance a solo manejar el deshacer en el caso de pegado con formato e ignoráramos otros atajos, botones de la barra de herramientas, etc., ¿reduciría el riesgo lo suficiente como para intentarlo?
Entendido; entre tu explicación y la de @david, comprendo la distinción. Simplemente, la mayoría de las veces no uso esos botones en el editor. Escribo cosas en el cuadro de texto usando el teclado de mi computadora (físico o en pantalla), y esto es manejado sin problemas por el navegador.
Es comprensible. Yo también tiendo a escribir el markdown en lugar de usar los botones de la barra de herramientas para eso, así que ese aspecto no es realmente un problema para mí. Solo mencioné las cosas de la barra de herramientas en el OP para señalar que no solo sucede al pegar texto formateado. Poder deshacer las acciones de la barra de herramientas no es súper importante porque el usuario está realizando esas acciones intencionalmente. Pero al pegar, el formato a menudo es incidental e inesperado, por lo que poder deshacer eso sería muy conveniente.
Aún no está programado, pero sí, parece que funciona. Creo que deberíamos cambiar nuestra implementación tanto para la barra de herramientas como para cosas como los atajos CTRL-B y las menciones.
Sin embargo, es un cambio bastante complejo, diría que llevaría entre 1 y 3 semanas de trabajo implementarlo todo. Hay muchas áreas:
Copiar y pegar imágenes
Subidas
Negrita / Cursiva
Enlaces
@menciones
#autocompletado
Apoyo este cambio, pero no estoy seguro de cuándo podemos programarlo… Supongo que no me importa incluirlo en nuestro próximo lanzamiento, ¿alguna objeción @codinghorror?
Me gusta que podrás usar CTRL-Z hasta llegar a un cuadro vacío en lugar de quedarte bloqueado en tu primera mención, enlace, etc.
Una cosa buena es que (en mi opinión) se puede hacer de forma incremental en lugar de tener que lanzarlo todo a la vez. Obviamente, no sé si ese será el caso desde una perspectiva técnica, pero desde la perspectiva del usuario creo que estaría bien. Algunas separaciones lógicas podrían ser:
Pegar texto que se formatea, incluyendo cosas como negrita, imágenes y enlaces
Acciones de la barra de herramientas, como negrita, ocultar detalles, difuminar spoilers, etc.
Siento que cada uno de esos grupos se podría hacer individualmente sin confundir a los usuarios, y personalmente ese sería el orden en el que lo implementaría.
Estoy programando este trabajo para nuestro próximo lanzamiento, lo que significa que lo tendremos resuelto en los próximos 6 meses aproximadamente, no sucederá de la noche a la mañana, pero progresaremos aquí.
Sí, te entiendo perfectamente, pero esto va a llevar un tiempo más.
Se ha convertido en una refactorización completa necesaria en el compositor. Nuestro plan a largo plazo es admitir una capa de abstracción diferente para el compositor, que ahora está MUY fuertemente unida a que siempre sea un elemento TEXTAREA.
El primer paso para desbloquear es admitir un compositor contenteditable que se vea y actúe como nuestra área de texto actual.
No creo que empecemos este proyecto en los próximos 3 meses, ya que tenemos otros 3 proyectos muy grandes antes, pero sí veo que comenzaremos este proyecto este año.
No te preocupes, solo estaba buscando una actualización.
Vaya, hasta ahora nunca había oído hablar de contenteditable. ¿Te importaría compartir una breve explicación técnica de por qué este cambio es necesario/deseable? Si no, no pasa nada, solo tengo curiosidad.
Es algo complicado, pero queremos entrar en el mundo de la experimentación con editores enriquecidos. Esto lo haría posible.
La razón por la que este trabajo está en la ruta crítica es que todos nuestros internos están fuertemente acoplados a una implementación específica (TEXTAREA). No tenemos una sola función para interactuar con el compositor, es más como copiar y pegar 20 implementaciones diferentes.
Lo que nos gustaría hacer es tener un pequeño componente “esqueleto” que diga:
Así es como se selecciona texto
Así es como se inserta texto
Y así sucesivamente… luego podemos reimplementar el esqueleto como un contenteditable o una implementación amigable con undo de TEXTAREA.
Sin embargo, hay que mover mucho código para permitir esto.
Esto no es ni de lejos tan completo como el trabajo a largo plazo que describió @sam. Pero creo que debería ayudar a corto plazo. Esto debería preservar el historial de deshacer al pegar texto enriquecido, al citar y al usar (la mayoría de) los botones/atajos de teclado del editor.
Ya está activo en Meta; avisa si notas algún problema.