Búsqueda de sitios web

javascript - execCommand() ahora está obsoleto, ¿cuál es la alternativa?


Mi intención era usar el método Document.execCommand() junto con el atributo contenteditable para construir mi editor WYSIWYG personalizado. Pero al revisar la documentación de Document.execCommand(), descubrí que ahora está obsoleto. ¿Cuál es la alternativa moderna (o existente) para él?

Respuesta #1

Respuesta para el año 2022-2025: El execCommand() está oficialmente obsoleto/depreciado, pero no hay alternativa. Así que si necesitas tener soporte para texto enriquecido, tienes que seguir usando execCommand() y averiguar por ti mismo qué funciona realmente con los navegadores que deseas soportar.

Tenga en cuenta que los agentes de usuario del mundo real (navegadores como Chrome, Firefox y Safari) no pueden dejar de dar soporte a execCommand() porque muchos servicios requieren soporte para ello. El triste estado de las cosas es que HTML5 no puede especificar ningún terreno común. Esto se debe a que los proveedores de navegadores no están de acuerdo en cómo debería funcionar execCommand(). Por lo tanto, no se puede especificar nada para HTML5, cuyo objetivo general es especificar todo lo que se necesita para la interoperabilidad completa de cualquier nuevo navegador que entre al mercado. Sin embargo, en mi opinión, HTML5 falla aquí porque la compatibilidad con execCommand() es en realidad requerida para que cualquier nuevo navegador entre al mercado. Por lo tanto, tendría sentido estandarizar al menos una de las implementaciones específicas de navegador como la oficial.

Todos los esfuerzos actuales de estandarización (Input Events 2, Clipboard API) ni siquiera intentan cubrir las funciones que execCommand() realmente realiza (por ejemplo, deshacer/rehacer, cambiar realmente el contenido dentro del rango de selección).

Las partes más difíciles de resolver son el movimiento del cursor, la selección de texto, diferentes comportamientos del IME (Editor de Métodos de Entrada) y el manejo del portapapeles nativo. Todos estos interactúan entre sí de diversas maneras dependiendo del navegador y el sistema operativo. Por ejemplo, el comportamiento que tiene Safari en iOS en iPad al escribir chino tradicional es totalmente diferente de Firefox en Windows con tailandés en mi experiencia. Lo cual, de nuevo, es totalmente diferente a Chrome que funciona en Chromebook mientras escribes en finlandés o introduces emojis con múltiples puntos UNICODE. Y como ninguna de las APIs JS disponibles revela todos los detalles, DEBES usar contenteditable y posiblemente execCommand() también, para que la mayoría de los navegadores reciban la entrada correcta del IME.

También ten en cuenta que, por ejemplo, Android GBoard también necesita conocer el texto circundante dentro del mismo contenido editable porque utiliza lógica de IA para determinar correctamente qué sugerencias de palabras dar al usuario mientras escribe texto, por lo que no puedes falsificar esto con un solo área de texto vacía e invisible debajo del cursor, porque eso carecería del contexto requerido. Eso no ha impedido que la gente intente hacer exactamente eso, pero falla en la práctica de varias maneras.

Esta situación ya ha estado ocurriendo durante más de cinco años, así que no esperes cambios rápidos tampoco.

Respuesta #2

Creé el Editor Avanzado para los propósitos de edición XML (HTML5 + XHTML) de mi plataforma. No diría que document.execCommand() está completamente obsoleto porque algunas partes todavía funcionan bien. Desafortunadamente, el problema principal para mí fue que los navegadores utilizan mucho código diferente para generar esos estilos que no son reconocidos por los lectores de pantalla utilizados por personas que son ciegas o casi ciegas.

Además, el error de tiempo más costoso que jamás tuve que conquistar fue un error de Gecko/Presto donde las selecciones visuales y técnicas (por qué no son lo mismo, no me lo pregunten) resultaban en que una parte del DOM se cambiara sin que el usuario lo pretendiera y esto se debía al hecho de que el recuento de píxeles por carácter es bajo, por lo que si el Editor Enriquecido no respetaba las selecciones visuales, un usuario se iría muy rápidamente. Eso requirió cuatro meses para ser conquistado y también hay otros errores.

En última instancia, es un esfuerzo duro pero alcanzable, aunque si planeas construir un editor HTML/XML como lo hice yo, deberías planear al menos seis meses si no solo planeas hacerlo correctamente, sino también probarlo hasta el punto de odiar el pastel, para luego que alguien venga y señale otro error más.

Tu enfoque principal en JavaScript debería estar en lo siguiente:

  • document.createRange()
  • document.createRange().surroundContents()
  • Node.cloneNode()
  • window.getSelection()
  • window.getSelection().getRangeAt(0).commonAncestorContainer
  • appendChild
  • insertBefore
  • insertBefore + nextSibling
  • replaceChild

En lugar del código inconsistente generado al usar execCommand() desde diferentes navegadores (que a menudo establece estilos en línea que complicarían el CSS de su sitio si no lo anulan por completo), debería ceñirse a usar los siguientes elementos sobre los cuales no solo puede tener control, sino que también son compatibles con lectores de pantalla:

  • em para énfasis (o "cursiva", <i> está en desuso).
  • strong para texto leído con fuerza (o "negrita", <b> está obsoleto).
  • u para subrayar (asegúrate de que tus anclajes tengan un estilo que los diferencie de los elementos u; u podría considerarse "obsoleto", aunque revertiré esto cuando arregle los estándares en los próximos diez años más o menos, úsalo de manera apropiada).
  • sub para texto en subíndice que aparece más abajo de lo normal.
  • sup para texto en línea de cena que aparece más verticalmente alto que el texto normal.
  • No uses el elemento <span> para añadir específicamente estos estilos, ya que los lectores de pantalla no entenderán ni revelarán comportamientos con errores; sigue siendo un elemento genérico en línea válido cuando se usa adecuadamente.

De hecho, he estado pensando en revisar mi Editor Enriquecido (ha estado recibiendo parches, aunque aún no ha sido reescrito correctamente), aunque eres bienvenido a mirar el código fuente cuando se cargue en una página del blog en el sitio enlazado en mi perfil. El proyecto original me llevó 11 meses, aunque con mi experiencia ahora creo que me tomaría unos tres o cuatro. Si hablas en serio, recomiendo encarecidamente mantenerse totalmente alejado de frameworks y bibliotecas. "¡Pero... pero, hacen la vida más fácil!" ... hasta que quieras usar una nueva versión y tengas que reescribir todo el proyecto. Usa JavaScript puro la primera vez y evita mantenimiento innecesario. ¡Buena suerte!


2021-09-24: Terminé retomando el trabajo en el Rich Editor II de hace aproximadamente un año y logré convertir el código que cambiaba estilos de 100,515 caracteres a ~6,000 y reducir la solicitud de archivos (ancho de banda efectivo después de la compresión) en un tercio completo. Aquí están las partes clave de ese éxito:

  1. El anchorNode y el focusNode pueden cambiar dependiendo de si seleccionas de izquierda a derecha o de derecha a izquierda. Como no encontraba ninguna justificación de por qué eso importaría (para mi plataforma), hice que un objeto (para anchorNode) a la izquierda y el objeto fn (para focusNode) siempre en el lado derecho.

  2. Resolvió el problema de Gecko/Presto usando ~1,700 caracteres; puede encontrarlo en el sitio (visite primero una página que tenga un formulario Rich).

  3. Para resolver el problema de seleccionar a través de numerosos intercambios con <s>, <sub>, <sup>, <u>, etc. (debes probar tanto ejemplos simples como extremadamente complicados), terminé usando window.getSelection().getRangeAt(0).commonAncestorContainer con cloneNode y luego, antes de procesar eso, eliminé lo que no estaba incluido en la selección. Luego simplemente usé window.getSelection().deleteFromDocument(); para eliminar la selección y reemplazarla con el nuevo elemento de estilo mediante document.createElement al que podía fácilmente appendChild la selección e insertarla en window.getSelection().getRangeAt(0).insertNode(id_('editor_rich_text').firstChild);.

Los navegadores Gecko como Waterfox, Pale Moon y el ahora completamente destruido Firefox te permiten seleccionar múltiples instancias de texto. Para hacerlo, simplemente mantén presionada la tecla Control para crear selecciones adicionales. Dado que realmente no ayuda de manera significativa (y estas cosas ya son lo bastante complicadas como para más), no me tomé la molestia de darle soporte en este momento.

Actualizaré mi plataforma hoy o este fin de semana (según la edición de esta publicación) para reflejar los nuevos cambios. Estoy manteniendo mucho del código antiguo debido a numerosos problemas con los navegadores Gecko. He ampliado la funcionalidad y resuelto numerosos errores y no tuve que recurrir a ningún truco y, como de costumbre, sin garaje (frameworks o bibliotecas).


26-09-2021: Para aquellos interesados en la funcionalidad de rehacer/deshacer, básicamente tendrán que recurrir a mantener versiones de texto de la parte del DOM que están editando. Claro, podría haber otras formas de implementarlo, aunque serían extremadamente complicadas. Básicamente, solo haces una copia del elemento principal del editor utilizando .cloneNode y luego, mientras está en memoria, usas algo como while (e.firstChild) {xml += new XMLSerializer().serializeToString(e.firstChild);}. Dado que lo almacenarás como texto, no tendrá las enormes implicaciones de memoria que tiene el DOM. Literalmente estarás reemplazando todo el DOM en el editor, así como rastreando cada iteración de un cambio, por lo que seguirá siendo un proyecto considerable. Para mi plataforma, no es necesario ahora, aunque quería cubrir esto ya que algunas personas lo han mencionado en los comentarios.

Respuesta #3

Puedes usar lo siguiente:

navigator.clipboard.writeText('text to be copied');

que hace exactamente lo mismo que document.execCommand("copy");

Respuesta #4

Parece que la alternativa será Eventos de Entrada Nivel 2.

Aunque es muy tentador crear un editor WYSIWYG hecho por mí mismo, personalmente me quedaré con execCommand hasta que llegue el nuevo estándar. Porque todos programaremos un editor completo nosotros mismos, en lugar de reutilizar soluciones actuales que funcionan.

Respuesta #5

La alternativa a document.execCommand() es la API del Portapapeles, a través de navigator.clipboard. Según MDN Web Docs (https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API):

Esta API está diseñada para reemplazar el acceso al portapapeles utilizando document.execCommand().

EDITAR: Como se mencionó en el comentario así como en el texto citado arriba, esto solo cumple un subconjunto de los requisitos (acceso al portapapeles).

Artículos relacionados