2011/10/28

Construyendo un Wysiwyg Editor con jQuery

En HTML, normalmente un textarea no es wysiwyg, pero existen plugins javascript, como CKEditor, NicEdit, entre otros, que ayudan a que lo sea. Se instala el plugin, se configura y listo. ¿Te animarías a hacerlo tú mismo?


WYSIWYG
Whay You See Is What You Get: lo que ves es lo que obtienes
Así es como se denomina a los editores que muestran la apariencia final del documento mientras es editado.

Buscando hacerme una herramienta para tomar notas con más facilidad, entré a explorar en este tema.

Antes, estaba envuelto por un halo misterioso. Suponía que sería una cuestión demasiado complicada. Descubrí que es más fácil de lo que parece.

Antes, para hacer editable un div, lo que se me ocurría era montar encima un elemento editable, como un input text, que se muestre cuando se necesite la edición. Pero, limitándome a eso, no veía cómo era posible mostrar en negrita o cursiva algo dentro de un elemento editable. Imaginaba que tendría que ver con algún tipo de magia desconocida que involucraría código muy complejo y sofisticado.

Resulta que es posible hacer que un div sea editable (¿por qué no difunden más esas cosas?).

Cuando un div es editable, está disponible un API que permite ejecutar comandos sobre su contenido (!).

De ese modo, hacer un editor wysiwyg se convierte en una cuestión muy, muy accesible, incluso para un programador como yo :-)

designMode
Al parecer, IE fue el que primero implementó la idea de que un elemento fuera editable, luego los otros navegadores acogieron la idea y ahora ya es algo estándar.

Esto se consigue haciendo que designMode="On" para el objeto que se desea editar.

Cuando se está en designMode="On", se pueden enviar comandos de formato usando la función execCommand. Estos permanecen activos hasta que se vuelven a enviar otra vez. O se aplican sobre el texto que estuviera seleccionado. Sí, como en Word. Hasta funciona deshacer con CTRL+Z

La idea básica
Una de las primeras guías que encontré usa un iframe y botones.

Pone el iframe en designMode="On". Hecho esto, se puede editar el contenido del iframe como si se estuviera en un textarea.

Los botones permiten invocar los comandos de formato.

Este es un ejemplo basado en: http://jsfiddle.net/Kxmaf/6/ :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>WYSIWYG Demo</title>

<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>

<style type="text/css">
input[type=button] {
  border: 1px solid #ccc;
}
#editor {
  width: 500px;
  height: 170px;
}
#bold {
  font-weight: bold;
}
#italic {
  font-style: italic;
}
</style>

<script type="text/javascript">
$(document).ready(function() {
  var cw = document.getElementById('editor').contentWindow;
  var doc = cw.document;
  doc.designMode = "on";
  doc.write('');
  doc.close();
  
  $('#bold').click(function() {
    cw.focus();// IE
    doc.execCommand('bold', false, false);
    cw.focus();
  });
  $('#italic').click(function() {
    cw.focus();// IE
    doc.execCommand('italic', false, false);
    cw.focus();
  });
  $('#fontname').change(function() {
    cw.focus();// IE
    doc.execCommand('fontname', false, $(this).val());
    cw.focus();
  });
});
</script>

</head>
<body>
  <h1>WYSIWYG Demo</h1>
  
  <div id="buttons">
    <input type="button" id="bold" value="B" />
    <input type="button" id="italic" value="I" />
    <select id="fontname">
      <option value="Arial">Arial</option>
      <option value="Comic Sans MS">Comic Sans MS</option>
      <option value="Courier New">Courier New</option>
      <option value="Monotype Corsiva">Monotype</option>
      <option value="Tahoma">Tahoma</option>
      <option value="Times">Times</option>
    </select>
  </div>
  <iframe id="editor"></iframe>
  
</body>
</html>

Mejorando
Es posible usar un div en lugar de un iframe. También se puede aprovechar más cosas de jQuery.

Este es un ejemplo basado en de77: jQuery Simple WYSIWYG Editor :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>WYSIWYG Demo</title>

<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>

<style type="text/css">
input[type=button] {
  border: 1px solid #ccc;
}
#editor {
  width: 500px;
  height: 170px;
  border: 1px solid #ccc;
}
#bold {
  font-weight: bold;
}
#italic {
  font-style: italic;
}
</style>

<script type="text/javascript">

$(document).ready(function() {
  function action(a,p) {
    $('#editor').focus();
    if (p == null) p = false;
    document.execCommand(a, null, p);
  }

  $('#editor').get(0).contentEditable = "true";
  
  $('#bold').click(function() {
    action('bold');
  });
  $('#italic').click(function() {
    action('italic');
  });
  $('#fontname').change(function() {
    action('fontname', $(this).val());
  });
  $('#html').click(function() {
    alert($('#editor').html());
  });
});
</script>

</head>
<body>
  <h1>WYSIWYG Demo</h1>
  
  <div id="buttons">
    <input type="button" id="bold" value="B" />
    <input type="button" id="italic" value="I" />
    <select id="fontname">
      <option value="Arial">Arial</option>
      <option value="Comic Sans MS">Comic Sans MS</option>
      <option value="Courier New">Courier New</option>
      <option value="Monotype Corsiva">Monotype</option>
      <option value="Tahoma">Tahoma</option>
      <option value="Times">Times</option>
    </select>
    <input type="button" id="html" value="HTML" />
  </div>
  <div id="editor"></div>
  
</body>
</html>

Me parece que esto puede ayudar a aclarar el tema para empezar. Ojalá le sirva de ayuda.

Referencias

2011/10/05

HTML + Javascript para usar cualquier framework

Todo o nada
Para hacer una aplicación web, se suele optar por alguna de las siguientes alternativas:

a) Usar completamente un framework propio.
b) Usar completamente un framework estándar.

La alternativa a) significa volver a implementar muchas de las cosas que ya se han resuelto en otros frameworks.

La alternativa b) significa depender completamente de lo que esté implementado en el framework elegido.

Pero pienso que hay otra alternativa. Una que no use la palabra completamente.

Imagine all the people
Imagine que no tiene que volver a escribir su aplicación web en otro lenguaje simplemente para usar algunas de las cosas que ofrece cierto framework escrito en ese lenguaje.

Imagine que no tiene que volver a escribir su aplicación web simplemente para usar algunas de las cosas que ofrece la siguiente versión del framework.

Imagine un framework en el que pudiera usar cualquier cosa que ya se hubiera implementado en otro framework, sin necesidad de volver a escribirlo.

Imagine que todos los frameworks pudieran trabajar juntos y usted pudiera escoger de esa feria de componentes los que mejor se adaptaran para cada cosa que necesitara. Todas las versiones y todos los lenguajes.

Cómo hacerlo
Se me ocurre al menos una manera.

Que el contenido dinámico se construya usando Javascript. Usando técnicas AJAX, se puede hacer una solicitud a cierto URL, con los parámetros que se requieran. En ese URL, un servidor procesa la solicitud, usando el framework y lenguaje de programación que sea, y devuelve una respuesta JSON. Con la respuesta, se construye la vista de la respuesta.

Pensando sobre eso, noto que en el modelo cliente-servidor del HTML, se obliga a que el navegador reemplace completamente el contenido de la página con la respuesta. Otra vez esa palabrita.

Quizás sería interesante extender la especificación HTML para admitir reemplazos parciales. AJAX es el testimonio de que eso se necesita. Flash también lo implementa (llamándolo carga dinámica).

Por el momento, la manera de hacer eso es con ayuda de Javascript (y alguna biblioteca como jQuery).

MVC
Un patrón de muy difundido en los frameworks actuales es MVC (modelo-vista-controlador).

Básicamente, se piensan las soluciones en términos de tres tipos de componentes: controladores, modelos y vistas.

Un controlador recibe la solicitud, determina qué hacer, utilizando los modelos necesarios y pasa los resultados a una vista.

Algunos dicen que la idea principal es que los diseñadores no se vean obligados a programar ni los programadores a diseñar. Pero, como nadie lo ha logrado (para hacer cualquier template se combina diseño con programación), pienso que se trata más de una cuestión de orden.

Si se usa Javascript para carga dinámica, lo que ocurre es que lo que devuelven las vistas puede ser usado no sólo para reemplazos totales, sino también para reemplazos parciales.

¿Por qué no se hace?
Eso mismo me pregunto.

He ido desarrollando estas ideas luego de observar como la comunidad Drupal está rehaciendo los módulos que funcionaban bien en Drupal 6 para que funcionen en Drupal 7. Es un riesgo. Se habla que algunos proyectos, como Perl, han perdido comunidad por hacer maniobras como esa.

Ya se ha iniciado la carrera hacia Drupal 8... llegado el momento, ¿volverán a reescribir los módulos?... ¿y así, sucesivamente?

Me parece que debe haber un camino mejor.

¿Qué le parece?

2011/10/04

Solucionar puerto 80 ocupado luego de Webmatrix

Resolver esto me ha tomado un tiempo. Espero le resulte de ayuda a alguien.

Luego lo desinstalar Webmatrix (La versión 1.0 me parece, en Windows 7), encontré que XAMPP no podía usar el puerto 80 como antes.

Con la idea de averiguar qué proceso lo ocupa, ejecuto en la consola de comandos, como administrador:

netstat -anb

pero aparece que no hay información disponible sobre el proceso que ocupa el puerto 80.

Usando la utilidad tcpview (de Sysinternals), veo que el proceso es el mismo System, con PID 4.

Hago telnet localhost 80 y veo que quién está atendiendo es Microsoft-HTTPAPI/2.0

Reviso en el Panel de Control, Herramientas Administrativas, Servicios, y desactivo "Servicio Agente remoto para Microsoft Web Deploy 2.0."

Eso era. Al parecer un issue de Webmatrix. Ahora XAMPP ya puede iniciar en el puerto 80.

Referencias