Cómo implementar un campo con editor de texto enriquecido HTML5 en una página Web.
En otras ocasiones hemos mostrado las diversas posibilidades de asignar el atributo contenteditable a una etiqueta HTML contenedora de texto.
Como ilustración de una aplicación casi completa, nos basaremos en los dos artículos anteriormente publicados, de los cuales tomaremos algunos apartados a modo de recordatorio y resumen de contenidos para, finalmente, mostrar el listado de un editor con las características que seguidamente se indicarán. Las referencias de los artículos aludidos son:
- Nuevos atributos HTML 5 para Rich-Text Editing (artículo de referencia 1)
- Comandos JavaScript para Rich-Text Editing de HTML 5 (artículo de referencia 2)
En concreto, el editor constará de las siguientes capacidades:
- Negrilla, itálica y subrayado de texto
- Formatos de cabecera completos
- Inserción de hipervínculos
- Colores de fuentes
- Tamaños de fuentes
- Listas y viñetas
- Ajustes – y centrados- de textos
- Ilustración del uso del Portapapeles
- Arrastrar y soltar archivos sobre el editor
- Cargar un documento desde el sistema local
- Guardar y recuperar en y del Local Storage
Para nuestro proyecto hemos utilizado WebMatrix 3, creando uno de tipo Sitio vacío al que denominaremos HTML5-EditorWysiwyg. En él, posteriormente, agregaremos un nuevo archivo de tipo HTML que también denominaremos HTML5-EditorWysiwyg.html.
Referencias
Las principales fuentes de referencia que recomendamos visitar son:
- http://www.w3.org/TR/2008/WD-html5-20080610/editing.html
- http://www.w3.org/TR/2011/WD-html5-20110525/editing.html#contenteditable
- https://developer.mozilla.org/en-US/docs/Rich-Text_Editing_in_Mozilla
- http://dev.opera.com/articles/tags/contentEditable
- http://marakana.com/s/using_the_html5_attribute_contenteditable_to_create_a_wysiwyg,1096/index.html
El atributo contenteditable (artículo de referencia 1)
Mediante éste atributo podremos realizar ediciones de textos con todo el potencial del lenguaje HTML en el interior de nuestras propias páginas Web. El texto en sí esta etiquetado con el mismo lenguaje de marcas que el documento HTML de la página Web.
Esto es, las áreas de texto pueden convertirse en áreas de edición de manera que podremos realizar los formateos y gestiones tales que –entre otros-, los citados con anterioridad y los recogidos en la tabla del apartado que sigue.
Por el contrario, no dispondremos de facilidades para trabajo con imágenes ni, de forma directa, acceso a archivos –abrir y guardar-. Algo que veremos cómo solventar.
El atributo "contenteditable" se mimetizaba, en versiones anteriores de HTML, mediante bibliotecas de JavaScript y similares, pero no es hasta su aparición en HTML 5 cuando ha comenzado a cobrar gran importancia por su simplicidad y potencia, siendo soportado por la totalidad de los principales navegadores de Internet –véase la tabla adjunta-
Chrome | Firefox | I. Explorer | Opera | Safari | Android |
6.0 | 3.5 | 6.0 | 8.0 | 3.2 | 3.0 |
La sintaxis es del todo simple:
<elemento contenteditable="true|false|inherit" […]>
- True: su contenido será editable
- False: no lo será
- Inherit: será editable si el elemento padre lo es –si hereda la editabilidad-
Ejemplos de elementos sobre los que se puede aplicar son todos los que atañen a contenidos de texto, como párrafos, secciones, divisiones, etc.
En los dos breves listados sintácticos que siguen se ilustra su uso.
Escribir aquí …
Aquí aplicado a una sección que incluye otros elementos como cabecera y parágrafo:
Título
Escribir aquí...
En el Listado 1, se muestra un área de edición muy simple, para implementarla, en el proyecto anteriormente iniciado, seleccione en el archivo HTML5-EditorWysiwyg.html todo su contenido y sustitúyalo por el del Listado 1. Posteriormente hacemos clic sobre un área libre del editor y según se trate de WebMatrix 3 o de Visual Studio seleccionaremos la opción de menú Iniciar en el Explorador o Ver en Explorador.
Listado 1: ejemplo simple de uso del atributo contenteditable
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" lang="es-es">
<title>contenteditable</title>
<style>
#textBox {
width: 600px;
height: 300px;
border: 2px #000000 solid;
padding: 10px;
overflow: scroll;
background-color: yellow;
}
</style>
</head>
<body><section id="textBox" contenteditable="true">
<h1 style="color:red">Título</h1>
<p>Escribir aquí...</p>
</section></body>
</html>
Ejecución de órdenes. Método execCommand (Artículo de referencia 2)
La sintaxis del método es:
object.execCommand (commandIdentifier, userInterface, value)
Devolverá true si se ejecutó correctamente y false de lo contrario.
Los parámetros que toma son:
- El nombre del comando a ejecutar –véase la tabla de más adelante-
- El interface de usuario que debería mostrarse. Hasta el presente no está implementado y siempre se pasa el parámetro false
- Algunos comandos necesitan algún argumento adicional, que se pasará aquí. De no ser así, se pasará una cadena de caracteres vacía –‘’-
Comando | Significado |
backColor | Cambia el color de fondo. |
bold | Permuta el texto resaltado activo/desactivado. |
copy | Copia el texto seleccionado al portapapeles. |
createLink | Crea un hiperenlace sobre el texto seleccionado. |
cut | Corta el texto seleccionado y lo copia al portapapeles. |
delete | Borra el texto seleccionado. |
fontName | Cambia la fuente. |
fontSize | Cambia el tamaño de la fuente. |
foreColor | Cambia el color del texto seleccionado. |
formatBlock | Formatea la selección en un nuevo bloque. |
indent | Adentra la selección. |
insertHorizontalRule | Inserta un elemento -etiqueta HTML- . |
insertHTML | Inserta etiquetas HTML personalizadas en forma de cadenas. |
insertImage | Inserta una imagen referenciada por una dirección URL. |
insertOrderedList | Inserta una lista ordenada –numerada-. |
insertUnorderedList | Inserta una lista sin ordenar –boliches-. |
insertParagraph | Inserta un nuevo párrafo. |
italic | Permuta entre texto seleccionado en itálica activo/desactivado. |
justifyCenter | Centra lo seleccionado. |
justifyFull | Justifica a ambos lados lo seleccionado. |
justifyLeft | Justifica a la izquierda lo seleccionado. |
justifyRight | Justifica a la derecha lo seleccionado. |
outdent | Desadentra lo seleccionado. |
paste | Pega el contenido del portapapeles. |
redo | Rehace la última operación. |
removeFormat | Retira el formato de lo seleccionado. |
selectAll | Selecciona todo el contenido editable de un elemento. |
strikethrough | Permuta entre tachado lo seleccionado activo/desactivado. |
styleWithCSS | Aplica estilos CSS a lo seleccionado. |
subscript | Permuta entre texto seleccionado en subíndice activo/desactivado. |
superscript | Permuta entre texto seleccionado en superíndice activo/desactivado. |
underline | Permuta entre texto seleccionado en subrayado activo/desactivado. |
undo | Deshace la última operación. |
unlink | Retira el hiperenlace del lugar seleccionado. |
Un editor avanzado HTML 5
Sus funcionalidades son las apuntadas al comienzo del artículo, los detalles de su programación, especificados en el Listado 2, se resumen en:
- Negrilla, itálica y subrayado: mediante botones de comando que ejecutan acciones del tipo execCommand con los parámetros correspondientes.
- Formato: de cabeceras, párrafo y preformateado. Se trata de una lista desplegable, que al producirse una selección llamará a la función formatoFuente con los parámetros correspondientes.
- Hiperenlace: consta de dos elementos, un área de entrada de la dirección URL y un botón de comando para aplicarla sobre el texto seleccionado en el área de edición del editor HTML. Al hacer clic sobre el botón se disparan las acciones de comprobación de la corrección de la sintaxis y el execCommand correspondiente –en su caso.
- Color: se aplicará el color seleccionado al texto elegido. Se trata de una lista desplegable, que al producirse una selección llamará a la función formatoFuente con los parámetros correspondientes.
- Bolillos y Lista: se aplica el estilo a párrafos seleccionados. Mediante botones de comando que ejecutan acciones del tipo execCommand con los parámetros correspondientes.
- Centro y Drcha.: se aplica el estilo a párrafos seleccionados. mediante botones de comando que ejecutan acciones del tipo execCommand con los parámetros correspondientes.
- Copiar, Cortar y Pegar: al y desde el Portapapeles del sistema local mediante botones de comando que ejecutan acciones del tipo execCommand con los parámetros correspondientes (Para el funcionamiento de cortar, copiar y pegar han de estar activados los accesos al Portapapeles del sistema local, por ejemplo el de Windows, en la configuración de seguridad de acceso a Internet del explorador, lo que recomendamos se haga sólo en el momento de la realización de la prueba. Otra opción es trabajar con scripts firmados por una entidad reconocida para tal fin.)
- Fuente: tamaños relativos, al estilo normal, media, grande, … Se trata de una lista desplegable, que al producirse una selección llamará a la función formatoFuente con los parámetros correspondientes.
- Insertar archivo de texto: se hace uso del sistema de HTML 5 de lectura de archivos, en este caso con la indicación type=’file´ y en el código de gestión JavaScript, indicando reader.readAsText(file), para forzar la lectura como archivo de texto.
- Guardar y Recuperar: en el "Local Storage" el contenido de texto en formato HTML. Obsérvese que utiliza el método del DOM –Document Object Model- innerHTML.
- Capacidades de arrastrar y soltar archivos de texto: se instalará el servicio en la carga del documento –window.onload- siendo el destinatario el área de edición y la función de respuesta –drop- llamará a la carga del archivo arrastrado, tras ignorar otras acciones por defecto.
Para implementar el editor, en el proyecto anteriormente iniciado seleccione en el archivo "HTML5-EditorWysiwyg.html" todo su contenido y sustitúyalo por el del Listado 2. Posteriormente hacemos clic sobre un área libre del editor y según se trate de WebMatrix 3 o de Visual Studio, seleccionaremos la opción de menú "Iniciar el Explorador" o "Ver en Explorador".
Listado 2: Código fuente de nuestro editor HTML 5.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" lang="es-es">
<title>Editor HTML (v.1.03)</title>
<style>
.opciones {
width: 720px;
border: 2px #000000 solid;
background-color: lightgray;
}
#textBox {
width: 700px;
height: 400px;
border: 2px #000000 solid;
padding: 10px;
overflow: scroll;
background-color: yellow;
}
</style>
<script>
function formatoFuente(sCmd, sValue) {
document.execCommand(sCmd, false, sValue);
}
function processFiles(files) {
var file = files[0];
var reader = new FileReader();
reader.onload = function (e) {
// Cuando se dispara este evento, los datos están disponibles.
// Los copiamos al <div> textBox de la página.
var output = document.getElementById("textBox");
output.innerHTML = e.target.result;
};
reader.readAsText(file);
}
// ---------------------------------------
var dropBox;
window.onload = function() {
dropBox = document.getElementById("textBox");
dropBox.ondragenter = ignoreDrag;
dropBox.ondragover = ignoreDrag;
dropBox.ondrop = drop;
}
function ignoreDrag(e) {
e.stopPropagation();
e.preventDefault();
}
function drop(e) {
e.stopPropagation();
e.preventDefault();
var data = e.dataTransfer;
var files = data.files;
processFiles(files);
}
// ----------------------------------------
function saveData() {
var localData = document.getElementById("textBox").innerHTML;
localStorage["lData"] = localData;
alert(localData);
}
function loadData() {
var localData = localStorage["lData"];
if (localData != null) {
document.getElementById("textBox").innerHTML = localData;
}
}
</script>
</head>
<body>
<section class="opciones">
<button onclick="document.execCommand('bold',false,'');">Negrilla</button>
<button onclick="document.execCommand('italic',false,'');">Itálica</button>
<button onclick="document.execCommand('underline',false,'');">Subrayado</button>
<select onchange="formatoFuente('formatblock',this[this.selectedIndex].value);this.selectedIndex=0;">
<option class="heading" selected>Formato</option>
<option value="<h1>">Cabecera <h1></option>
<option value="<h2>">Título <h2></option>
<option value="<h3>">Título <h3></option>
<option value="<h4>">Título <h4></option>
<option value="<h5>">Título <h5></option>
<option value="<h6>">Título <h6></option>
<option value="<p>">Párrafo <p></option>
<option value="<pre>">Preformateado <pre></option>
</select>
<button onclick="if (document.getElementById('szURL').checkValidity()) {
document.execCommand('CreateLink',false,document.getElementById('szURL').value);}">Hiperenlace</button>
<input type="url" id="szURL" required>
<select onchange="formatoFuente('forecolor',this[this.selectedIndex].value);this.selectedIndex=0;">
<option class="heading" selected>Color</option>
<option value="red">Rojo</option>
<option value="blue">Azul</option>
<option value="green">Verde</option>
<option value="black">Negro</option>
</select>
</section>
<section class="opciones">
<button onclick="document.execCommand('insertunorderedlist',false,'');">Bolillos</button>
<button onclick="document.execCommand('insertorderedlist',false,'');">Lista</button>
<button onclick="document.execCommand('justifyleft',false,'');">Izqda.</button>
<button onclick="document.execCommand('justifycenter',false,'');">Centro</button>
<button onclick="document.execCommand('justifyright',false,'');">Drcha.</button>
<button onclick="document.execCommand('cut',false,'');">Cortar</button>
<button onclick="document.execCommand('copy',false,'');">Copiar</button>
<button onclick="document.execCommand('paste',false,'');">Pegar</button>
<select onchange="formatoFuente('fontsize',this[this.selectedIndex].value);this.selectedIndex=0;">
<option class="heading" selected>Fuente</option>
<option value="1">Muy pequeña</option>
<option value="2">Pequeña</option>
<option value="3">Normal</option>
<option value="4">Media</option>
<option value="5">Grande</option>
<option value="6">Muy grande</option>
<option value="7">Enorme</option>
</select>
</section>
<div id="textBox" contenteditable="true">
<h1 style="color:red">Título</h1>
<p>Escribir aquí...</p>
</div>
<section class="opciones">
<input id="fileInput" type="file" onchange="processFiles(this.files)">...Insertar archivo de texto
</section>
<div class="opciones">
<button onclick="saveData()">Guardar</button>
<button onclick="loadData()">Recuperar</button>
</div>
</body>
</html>
Conclusiones
En el presente artículo hemos visto la implementación de editor de textos HTML en una página web con múltiples capacidades, que hemos desglosado pertinentemente para su posible aplicación personalizada.
Esperamos que todo lo expuesto les haya servido de ayuda. Hasta nuestro próximo artículo, felices horas de programación.
Jaime Peña Tresancos
Escritor. Colaborador habitual de revistas de tecnología y experto en nuevas tec...