Esta semana, a raíz de un mensaje en la lista de correo de Made in Flex, recordé una de las primeras aplicaciones que hice en Flex hace ya dos años con lo cual me lancé a recuperar aquél código, limpiarlo de cosas supérfluas y publicarlo. Os dejo también el enlace a un post mio en la lista Flexcoders donde explicaba como hacerlo, de hecho ha sido mucha la gente que, a partir de ese post, me ha escrito preguntando detalles.
Para los puristas, os aviso de antemano que puede haber cosas que no funcionen bien, código extraño y mil historias más, es un código que tiene dos años, si hacéis cuentas veréis que justo estos días Flex2 cumple dos años. Sí, lo comencé con las primeras betas de aquella versión. Lo único que he hecho ha sido crearlo en Flex3 y dejar la aplicación limpia para que se vea el funcionamiento. Si me váis a dejar un comentario diciendo que tal o cual cosa no funciona bien, podéis ahorrárosla.
Como una imagen vale más que mil palabras, aquí tienes el ejemplo y el código fuente de todo el proyecto.
Todos a los que en algún momento se nos ocurrió utilizar Flex para crear un gestor de contenidos nos hemos dado con un grave problema en la frente: el componente ideal para escribir y actualizar contenidos, RichTextEditor, NO permite, por defecto, insertar imágenes, con lo cual pierde prácticamente su utilidad. Escarbando en la ayuda, sin embargo, te das cuenta de que entre los tag HTML soportados por el componente Textarea se encuentra <IMG>, con lo que, a priori, nada impediría insertar una imagen. En efecto así es y en eso se basa todo este artículo/proyecto. Un detalle importante es que la utilización de imágenes no está bien conseguida en el propio Flash Player, con lo que si comenzamos a añadir y quitar imágenes llegará un momento en el que todo el Textarea será inestable y hará cosas extrañas.
El proyecto se basa en dos componentes, nuestro editor de texto y un explorador de archivos. Desde el editor tendremos un botón Insertar imagen que abrirá un explorador al más puro estilo del escritorio del sistema operativo donde nos mostrará los archivos que tenemos en el servidor, pudiendo subir y eliminar. La lógica del explorador con el servidor la he eliminado al máximo, dejando sólamente unos XML estáticos que listan las carpetas e imágenes disponibles. Para hacerlo bien haríais un script con salida similar a esta pero que liste lo que en realidad hubiese en una ruta de tu servidor.
Nuestro editor de texto
Intentaré explicar como hice todo el proceso, pero fue hace bastante tiempo así que es posible que se me olvide algún detalle.
La idea era hacer un editor avanzado, con las caracteristicas que le faltaban al RichTextEditor original:
- Insertar imágenes.
- Posibilidad de añadir datos tabulados (que no tablas como tales).
- Cambiar el color de fondo del editor para, por ejemplo, crear texto en color blanco.
- Eliminar todo el texto (e imágenes).
- Editor avanzado de links.
- Botón guardar texto (lo insertaría en tu base de datos)
Partimos para ello de un RichTextEditor al que le quitamos el botón predefinido de Añadir link y añadimos nuestros nuevos botones. Siguiendo el código entenderás lo que hacen, por lo que nos centraremos en el de imágenes que es el objeto del artículo. Primero os explico en qué consiste el botón de tabular datos. Es muy sencillo. Si quisiésemos, en el RichTextEditor, crear una tabla de valores con el tabulador, no podríamos, ya que al presionar tabulador saldría el foco del Textarea de escribir y se iría, por defecto, al selector de fuente. Para solucionarlo añadimos un botón que lo único que hace es añadir un carácter de tabulación (t) en el texto, con lo que comprobaréis que ya puedes tabular datos perfectamente. Muy útil el truco.
Pasemos pues al botón de insertar imágenes. El botón, tal y como expliqué anteriormente, abre el popup del explorador de archivos, con lo que esta parte la veremos en la siguiente sección. Cuando en el explorador seleccionamos la imagen a insertar se devuelve el control al editor y es éste el que añade la imagen. Para añadir la imagen inserta en la posición del cursor el tag <IMG> con los parámetros necesarios. Aparentemente no tiene más truco, pero al empezar a probar cosas nos damos cuenta que sí que lo tiene.
Para empezar, si guardamos el htmltext de este RichTextEditor en la base de datos y posteriormente intentamos recuperarlo recibiremos un desagradable error de validación XML. Quiero aclarar antes de nada, que este error me ocurría en aquél entonces, quizás, ojalá, las ultimas versiones de Flex lo hayan solucionado, te ahorraría muchos problemas. La causa del error de validación era que internamente, aunque tu añadieses un tag <img … /> (o <img…></img>) válido, el editor te devolvía siempre <img .. > , es decir, el XML sin cerrar, con lo cual al cargarlo de nuevo saltaba error de validación. Para solucionar este problema creamos un método desProcesaTexto que lo que hace es convertir todos los tags <img..> no válidos a tag válidos, con lo que tenemos el primer problema resuelto. Utilizando expresiones regulares será extremadamente sencillo.
var pattern:RegExp = /<IMG([^>]*)>/gi; texto=texto.replace(pattern, "<IMG $1 ></IMG>");
Segundo problema. Una vez insertamos una imagen, ¿cómo podemos quitarla o modificarla? Aquí viene parte del truco. La idea, básicamente, es añadir a cada imagen un link de manera que al hacer click en ella se nos abra un popup que nos permita eliminar la imagen o modificar sus atributos. Esto genera otro inconveniente. Cuando queremos recuperar el contenido del Textarea para guardarlo en la base de datos debemos eliminar estos links falsos añadidos para la interfaz de usuario, pero que no queremos que salgan cuando se muestre el texto. Por contra, cuando cargamos un texto desde la base de datos debemos procesar los atributos de imágenes para añadirles este link y podamos operar con ellos.
var temp:XML=XML("<texto>"+texto+"</texto>"); var allTags: XMLList; var item:XML; var tempitem:XML;allTags= temp..IMG; for each(item in allTags) { var xlcParent:XMLListCollection = new XMLListCollection(item.parent().parent().children()); tempitem=XML(xlcParent.toXMLString()); xlcParent.setItemAt(item, 0); }
Como se aprecia en el código, bucamos todos los tags <IMG> y, asumiendo que todos tendrán un tag <A> anterior, reemplazamos el nodo <A> completo por el <IMG> y todo solucionado, más sencillo de lo que parece una vez se entiende el procedimiento.
Para contemplar estas peculiaridades cada vez que asignamos el texto al componente o cada vez que lo recuperamos, tenemos los siguientes métodos:
public function getHtmlText():String{ return desProcesaTexto(this.htmlText); } public function setHtmlText(texto:String):void{ this.htmlText=procesaTexto(texto); }
No hay mucho más que explicar. Como peculiaridad, veremos como procesaríamos los tags <IMG> cuando cargamos un texto nuevo en el componente. La idea, básicamente, es añadir el link que nos permita modificarla, pero este link necesita conocer los datos de la imagen (src, width, height..).
allTags= temp..IMG; for each(item in allTags) { var xlcParent:XMLListCollection = new XMLListCollection(item.parent().children()); var iIndex:int = xlcParent.getItemIndex(item); idlink=Math.round((Math.random()*100000)*(Math.random()*100000)); nuevoNodo="<A href="event:IMAGEN##||##"+item.@ID+"##||##"+item.@SRC+"##||##"+item.@WIDTH + "##||##"+item.@HEIGHT+"##||##"+item.@VSPACE+"##||##"+item.@HSPACE+"##||##"+item.@ALIGN + "##||##"+idlink.toString()+"" ID=""+idlink.toString()+"">"+xlcParent.toXMLString()+"</A>"; xlcParent.setItemAt(XML(nuevoNodo), iIndex); }
Sencillo.
El explorador de archivos
El explorador de archivos es un componente bastante resultón que, si lo trabajas un poco, te puede solucionar muchas tareas. Igual que el Explorador de Archivos de Windows, tienes a la izquierda un árbol de directorios y a la derecha los archivos de la carpeta seleccionada y sus detalles. Arriba tenemos botones para subir archivos nuevos y crear nuevas carpetas (la lógica de estos botones es cosa tuya) y, sobre todo, un combo para cambiar el modo de ver los archivos de manera que puedes ver la lista de los mismos o las miniaturas. Si, si listas imágenes verás un thumbnail de las mismas, perfecto para nuestro editor. No voy a enrollarme mucho más con el funcionamiento ya que en el código fuente tienes todo lo necesario. El evento interesante es el doble click sobre un archivo, que devuelve el control a una nueva ventana donde puede configurar los parametros de la imagen a insertar. Con el ejemplo lo entenderas.
En tu editor deberás crear los métodos adecuados en el servidor para listar las carpetas y archivos de tu directorio de uploads si quieres que todo sea dinámico y el usuario pueda organizarse por su cuenta los archivos.
Tal como había comentado, no he sido tan explícito como en otras ocasiones. Si tienes algún problema no dudéis en dejar un comentario e intentaré solucionarlo a la mayor brevedad posible.
Aquí tienes el ejemplo y el código fuente de todo el proyecto.