Yahoo! UI y Yahoo! Patterns beta 2

Yahoo! UI Beta 2
Acaba de salir una nueva revisión de la Yahoo! User Interface y los Design Patterns . Se han añadido unos cuantos controles de interfaz, como por ejemplo lo menús, módulos, paneles, cuadros de diálogo, y tooltips, un control de autocompletado, ayudas para la normalización de CSS, de layouts y diseño así como un montón de nuevos patrones.

Merece la pena echarles un vistazo. Yo he usado la versión anterior y he de decir que funciona muy bien (aunque un poco pesada de tamaño).

Tutoriales sobre AJAX

Max Kiesler ha recopilado más de 60 enlaces a tutoriales sobre AJAX, que vienen a unirse a los otros 30 que publicó anteriormente.
En ellos se cubren multitud de aspectos de la programación y uso de AJAX como por ejemplo los indicadores de actividad, los Bookmarklets, Chats, comunicación cliente-servidor, Drag and Drop, carga dinámica de contenido, Forms y Autocompletado, Imagenes y gallerias, listas ordenables, frameworks, etc.

Sin duda un buen enlace para tener a un solo click en nuestro del.icio.us.

Puntos a tener en cuenta cuando uses AJAX

Hace tiempo que encontre el enlace, pero no lo había leido con detenimiento hasta hoy, tras encontrarlo en La Taberna del Turco. Si estais pensando en usar masivamente AJAX para vuestro proyecto, os recomiendo su lectura. La lista es editable, por lo que puede ir creciendo con interesantes aportaciones.

Para los que no controlen mucho el inglés, me permito humildemente hacer aquí una breve traducción/interpretación en castellano:

Errores en el uso de AJAX en una aplicación web

Usar AJAX por ser “AJAX”

Sabemos que AJAX mola, que es novedad y que a los desarrolladores nos encanta jugar con lo último, pero ante todo AJAX es una herramienta, no un juguete. Muchas de las implementaciones que encontramos usando AJAX no son realmente necesarias para mejorar la usabilidad o la experiencia del usuario, sino unicamente experimentos para comprobar qué puede hacer AJAX o empeños de ponerlo donde realmente no se necesita.

Hacer inservible el botón de volver atrás

El botón de retroceder (del navegador) es muy util en la navegación de una interfaz web. Desafortunadamente, no se lleva muy bien con las aplicaciones Javascript. Mantener la funcionalidad asociada a este botón es una de las razones para no realizar una aplicación completemante basada en Javascript.

Sin embargo, se debe tener en cuenta que un buen diseño web debe poner al alcance del usuario todo lo que necesita para navegar correctamente por el sitio y nunca depender de los botones o controles existentes en el navegador.

No mostrar inmediatamente señales del progreso de una operación

Si algo en lo que hacemos click lanza una acción mediante AJAX, la aplicación debe dar pistas visuales de que algo está ocurriendo (ya que el navegador no lo hará ).

Un ejemplo de esto, es la etiqueta roja que aparece en la esquina superior derecha en Gmail mostrando el texto “loading”, cada vez que la interacción con el servidor se hace mediante AJAX.

No pensar en la gente desconectada (offline)

A medida que los limites de las aplicaciones web se van superando, se va haciendo más patente la posibilidad de mover todas las aplicaciones a la web. La disponibilidad es mejor, el modelo de acceso desde cualquier parte del mundo es genial, el mantenimiento y la configuración realmente faciles, la curva de aprendizaje de la interfaz de usuario es pequeña.

Sin embargo, la gente que dispone de malas o lentas conexiones a la red o que simplemente no desean estar conectados tambien deben tener su sitio. Simplemente porque la tecnología avance no significa que las personas esten preparadas y deseando ir a su mismo ritmo.

El diseño de aplicaciones web debe considerar al menos el acceso offline (desconectado). Con GMail es POP (con lo que puedes descargartelo en tu cliente de correo de escritorio y leerlo offline), Backpackit tiene integracion con SMS, por poner algunos ejemplos. En el mundo empresarial, sus servicios web.

No me hagas esperar

Las tabs de Firefox, me permiten administrar varias “esperas” a sitios web y normalmente solo tengo que esperar para la navegación en una página.
Las aplicaciones AJAX combinadas con una conexion/ancho de banda/latencia pobre , pueden presentar un enorme problema de tiempos de espera al movernos por su interfaz, ya que cada vez que hago algo tengo que esperar la respuesta del servidor. Que Dios me ayude si tiene que llegar hasta el disco del servidor antes de que yo pueda continuar…

Enviar de forma insegura información sensible

La seguridad en las aplicaciones AJAX está sujeta a las mismas reglas que la de cualquier otra aplicación web, excepto que al poder comunicarse de forma asíncrona con el servidor, pueden tender a estar hechas con código frágil y poco seguro. Es muy importante que todo el trafico que envía/recibe nuestra aplicación sea comprobado para que la seguridad no se vea comprometida.

Asumir que el desarrollo AJAX sólo es para una plataforma

El desarrollo AJAX es multiplataforma. De hecho funciona con el motor javascript del IE, con el motor de Mozilla, con el motor de Safari y con otros que pueden convertirse en fuertes opciones.
No es suficiente programar siguiendo los estándares Javascript (sobre todo sabiendo que existe IE), se debe probar la aplicación en el máximo número de plataformas posible.

En el desarrollo con Javascript nos encontramos con un serio problema: la implementación defectuosa del motor de JS de Internet Explorer (aunque existen herramientas para ayudar). Pero cualquier desarrollador ya estará acostumbrado a lidiar con este tipo de problemas (tambien con CSS por ejemplo)

Olvidar que la aplicación puede estar siendo usada por varias personas a la vez

Cuando se desarrolla una aplicación web de intrante, es necesario tener en cuenta que va estar siendo usada por más de una persona a la vez. Si la información que se muestra se almacena dinámicamente en una base de datos, asegurate que esto no te crea “problemas”.

Demasiado código, hace que el navegador sea lento

AJAX trae una nueva forma de hacer aplicaciones javascript mucho más interesantes, pero desafortunadamente esto a veces tambien significa “más código funcionando”.
Más código funcionando significa más trabajo para el navegador, lo que provoca que en muchas webs con uso intensivo de Javascript, especialmente las mal programadas, necesites la última CPU del mercado para poder navegar por ella.
De hecho, el problema de uso de CPU realmente ha sido un limite para la funcionalidad de Javascript en el pasado y el hecho de tener CPUs más potentes en la actualidad, no significa que el problema haya desaparecido.

No tener un plan para aquellos que no usen o habiliten Javascript

Según las estadísticas de de uso de navegadores de W3 schools el 11% de los visitantes a una web, no disponen de Javascript. Así que si tu aplicación web depende por completo de esta tecnología, parece ser que potencialmente has perdido a una décima parte de tu audiencia.

Hacer parpadear o cambiar partes de la página de forma inesperada

La A de inicio de AJAX viene de la palabra “Asynchronous” (asíncrono). El problema con los mensajes asíncronos es que pueden ser confusos cuando se muestran de forma inesperada.
Los cambios asíncronos en la página deben ocurrir en zonas bien definidas y deben usarse con buen criterio. Los efectos y parpadeos deben estar limitados a esas áreas y deben tener un sentido.
Desde luego lo que no tiene mucho sentido es que volvamos a los tiempos de la etiqueta “blink” de html y a las “webs parpadeantes”.

No usar enlaces que pueda pasar a un amigo o añadir a favoritos

Otra característica fantástica de los sitios web es que puedo pasar su URL a otra gente para que puedan ver exactamente el mismo contenido que yo. Tambien puedo guardar en mis favoritos la URL para regresar posteriormente.
Javascript, y por lo tanto AJAX, trae grandes problemas a este modelo de uso. Al generar dinámicamente la página con Javascript en vez de desde el servidor, la url no necesariamente apunta al mismo contenido, y no puede ser usada para lo que estamos acostumbrados.
Esta es una característica que no se debe perder y de hecho muchas aplicaciones AJAX incluyen “permalinks” (urls especialmente generadas) que solucionan este problema.
Algunos toolkits (como por ejemplo dojo), incluyen facilidades para conseguir esto.

Realizando operaciones por lotes de forma asíncrona

AJAX permite que la edición de campos de un formulario se realice de forma inmediata, pero so puede acarrear muchos problemas.
Por ejemplo, desmarco una lista de “check boxes”, cada una de las cuales es enviada de forma asíncrona al servidor. Pierdo mi habilidad para saber el estado en el que se encuentran los cambios en las “checkbox” y el aluvión de indicaciones de cambio de cada checkbox puede ser molesto y desconcertante.

Mover la posición vertical en la pagina y hacerme perder la situación donde me encontraba

Otro problema de insertar texto en una pagina de forma dinámica es que puede afectar al scroll. Me encuentro felizmente leyendo un artículo o moviendome por una enorme lista, y una petición Javascript asíncrona decide de repente cortar un párrafo justo encima de lo que estoy leyendo, haciendome perder la posición. Obviamente esto es algo molesto y me hace perder el tiempo intentando volver a encontrar la posición donde estaba.
Pero evidemente esta es una forma bastante estúpida de programar una página, tenga o no AJAX.

Inventar nuevos “estándares” de interacción con la interfaz

Un gran error que es fácil cometer co AJAX es: “haz click en esta cosa nada obvia para conseguir este nada obvio resultado”. Los usarios de una aplicación pueden darse cuenta de que cuando haces click y mantienes pulsado sobre este div, lo puedes arrastrar y dejar permanentemente en esta otra posición, pero eso no es algo que esté por defecto en la experiencia común de los usuarios. De esta forma se incrementa el tiempo y la dificultad para aprender a usar una aplicación, lo cual es un punto muy negativo para la misma.

Blockear el acceso a la información a nuestras amigas las arañas

Las aplicaciones AJAX que cargan una gran cantidad de texto sin recargar la página pueden ser un gran problema para los motores de búsqueda.
Volvemos al mismo problema que con la URL y el botó atrás. Si los usuarios pueden llegar a través de los motores de búsqueda el texto de la aplicación debe estar de alguna manera disponible para que lo lean las arañas (spiders) de los buscadores.

Conjuntos de caracteres

Uno de los grandes problemas al usar AJAX es la carencia de este de soporte para juegos de caracteres. Siempre deberías establecer el juego de caracteres a usar en el servidor así como codificar todos los datos usados con Javascript. Usa ISO-8859-1 si tu aplicación sólo usa inglés o español, o UTF-8 si usas caracteres especiales como æ, ø y å.
Nota: Hoy en día es buena idea usar siempre el juego de caracteres utf-8 ya que soporta un gran variedad de idiomas.

Cambio del estado con enlaces (peticiones GET)

La gran mayoría de aplicaciones AJAX tienden a usar simplemente el método GET cuando realizan peticiones con XMLHTTPRequest.
Sin embargo, los estándares W3C dicen que el método GET debe ser usado únicamente para obtener datos y el POST únicamente para enviar datos.
Aunque esto no representa una diferencia notable para el usuario final, estos estándares deben seguir siendo usados para evitar problemas with robots o programas como por ejemplo el Google Web Accelerator.

No trasnferir los cambios locales a otras partes de la página

Al darte AJAX/Javascript tal control sobre el contenido de la página, es fácil enfocarse demasiado en una pequeña zona del mismo y perder la imagen de la página global.
Un ejemplo de esto, es el título de Backpackit. Si cambias el título de una página de Backpackit, inmediatamente se reemplaz el título, incluso en la zona de la derecha, pero no cambian el contenido de la etiqueta title en el head de la página.
Con AJAX debes tener siempre en mente el modelo completo de la página aunque los cambios sean pequeñs y localizados.

Aviso de errores

En una aplicación tradicional de lado servidor, dispones de visibilidad para cada excepción, puedes guardar registro de cada evento o estadística o incluso guardar y ver (si lo deseas) el HTML que el navegador está mostrando.
Con las aplicaciones en el lado cliente, puede pasar que no tengas ni idea de que algo ha ido mal si desconoces cómo programar correctamente y guardar esas excepciones (errores) que se producen remotamente (en el navegador del cliente) en tu servidor.

Retorno de la inversión

A veces AJAX puede incrementar de forma espectacular la usabilidad de una aplicación (un buen ejemplo puede ser la forma de votar usando estrellas en Netflix), pero lo más común es ver ejemplos de caras aplicaciones en lado cliente (rich-client applications) que realmente no mejoran lo que seria su correspondiente versión en HTML simple.

Imitar el comportamiento de navegación del navegador de forma errónea

Un ejemplo de esto es el sistema de paginación que ofrece en su pagina inicial Blinklist.
Cuando haces click, ves que se carga otra página de link, AJAX reemplaza el número de página. Pero si estás acostumbrado a la experienca de uso del navegador, probablemente esperes aparecer en la parte superior de la página cuando pulses el botón de siguiente, algo que la aplicación Javascript no hace.
De hecho, BlinkList se anticipa a esto e intenta contraactuar manipulando tu scroll para llevarte a la parte de arriba de la página. Pero es muy lento, por lo que si intentas bajar, no te deja.

Pero una vez más, esta es una forma muy estúpida de programar una página tenga o no AJAX.

Otra herramienta más

Parece que todo el mundo ha olvidad que AJAX es simplemente otra herramienta más entre todas las que tenemos para el desarrollo web. Puedes usarlo o no y puedes usarlo mal o bien, como cualquier otra.
La regla 80/20 siempre es valida para las aplicaciones (si eres capaz de cubrir el 80% de lo que tus usuarios quieren/necesitan entonces tienes una aplicación viable) y si pierdes un 11% de tu audiencia porque no activan el soporte javascript de su navegador, entonces deberás preguntarte si el cambiar tu aplicacion te va a permitir capturar ese 11% o quedarte con el 89% que lo usa actualmente y cambiar a algo distinto.
Las aplicaciones web deben beneficiarse de todos los trucos que las permitan funcionar de forma más rápida y eficiente. Si usar javascript en una parte, AJAX en otra y ASP por detras ayuda a conseguirlo, entonces hagamoslo.

La potencia de JQuery

Me encuentro en el blog de jquery, este interesante reto: Encontrar todos los “li” bajo dos elementos diferentes (usando su id como referencia) y asignar una funcion al evento onClick de los mismos que cambie el color del texto de los “li”. Suena un poco lioso… :P

Estas son las distintas formas de resolverlo usando las librerías javascript más populares:

Behaviour + Prototype

Behaviour.register({
  '#item li': function(element) {
    Event.observe(element, 'click', function(event) {
      Event.element(element).setStyle({color: '#c00'});
    });
  },

  '#otheritem li': function(element) {
    Event.observe(element, 'click', function(event) {
      Event.element(element).setStyle({color: '#c00'});
    });
  }
});

Prototype 1.5.0

$$('#item li, #otheritem li').each(function(li){
  Event.observe(li, 'click', function(event) {
    Event.element(li).setStyle({color: '#c00'});
  });
});

Event:Selectors

EventSelectors.start({
  '#item li:click, #otheritem li:click': function(){
    this.setStyle({'color': '#c00'});
  }
});

JQuery

$("#item li, #otheritem li").click(function(){
  this.css('color', '#c00');
});

La verdad es que me he quedado impresionado con la simplicidad de la solución generada con JQuery. Creo que el código habla por sí mismo…

AJAX no es apto para inexpertos

Navegando por Internet con la visión de programador, a veces te encuentras verdaderas joyas cuando miras el código de un sitio. Como esta:

function saveform()
{
  var firstName = escapeSql(mainForm.elements.txtFirstName.value);
  var lastName = escapeSql(mainForm.elements.txtLastName.value);
  /* ... */
  var offerCode = escapeSql(mainForm.elements.txtOfferCode.value);

  var code =
  '  $cn = mssql_connect($DB_SERVER, $DB_USERNAME, $DB_PASSWORD)           ' +
  '          or die("ERROR: Cannot Connect to $DB_SERVER");                ' +
  '  $db = mssql_select_db($DB_NAME, $cn);                                 ' +
  '                                                                        ' +
  '  if (mssql_query("SELECT 1 FROM APPS WHERE SSN=\''+ssn+'\'", $cn)) ' +
  '  { $ins = false; }                                                     ' +
  '  else                                                                  ' +
  '  { $ins = true; }                                                      ' +
  '                                                                        ' +
  '  if ($ins) {                                                           ' +
  '    $sql = "INSERT INTO APPS (FIRSTNM, LASTNM, ..., OFFERCD) VALUES ("; ' +
  '    $sql+= "\''+firstName+'\',";                                        ' +
  '    $sql+= "\''+lastName+'\',";                                         ' +
  '    $sql+= "\''+offerCode+'\')";                                        ' +
  '                                                                        ' +
  '  /* ... */                                                             ' +
  '                                                                        ' +
  '  mssql_query($sql, $cn);                                               ' +
  '  mssql_close($cn);                                                     ';

  execPhp(code);
}

Desde luego, no querría estar en su piel en el momento en el que un “malintencionado” programador encontrara esta forma tan sencilla de acceder a su base de datos… :P
Hay de tó

Thickbox, “popups” con clase

thickbox

Cody Lindley, el creador de lightbox, nos muestra su nueva creación: Thickbox.

Basandose en el código de lightbox, lo ha extendido para dar soporte a otros tipos de archivo además de las imágenes. En concreto:

  • * .jpg
  • * .jpeg
  • * .gif
  • * .png
  • * .htm
  • * .html

Pero con un poco de experiencia en javascript es facil modificarlo y ampliar la lista de tipos que se pueden usar.
La verdad es que estética y funcionalmente es genial.

Ventajas:Te deja un html totalmente limpio y separado del javascript. No pesa demasiado ya que se han pasado de prototype a JQuery, ahorrando unos 20 KB. Visualmente es espectacular.

Inconvenientes: Es javascript (incompatibilidades). Puede resultar un poco lento en algunos navegadores/sistemas.

Provincias y localidades de España / Códigos postales

Casi todos nos habremos encontrado con este problema a la hora de abordar el desarrollo de algunas aplicaciones:
Tener la lista de provincias de España en la base de datos, poder saber qué provincia es a partir del código postal, tener el listado de poblaciones de una determinada provincia.
Seguro que a más de uno le viene bien lo que dejo aquí ;)

<?php

$provincias = array (
	 array ('id' => "01", "nombre" => "ALAVA"),
	 array ('id' => "02", "nombre" => "ALBACETE"),
	 array ('id' => "03", "nombre" => "ALICANTE"),
	 array ('id' => "04", "nombre" => "ALMERIA"),
	 array ('id' => "33", "nombre" => "ASTURIAS"),
	 array ('id' => "05", "nombre" => "AVILA"),
	 array ('id' => "06", "nombre" => "BADAJOZ"),
	 array ('id' => "08", "nombre" => "BARCELONA"),
	 array ('id' => "09", "nombre" => "BURGOS"),
	 array ('id' => "10", "nombre" => "CACERES"),
	 array ('id' => "11", "nombre" => "CADIZ"),
	 array ('id' => "39", "nombre" => "CANTABRIA"),
	 array ('id' => "12", "nombre" => "CASTELLON"),
	 array ('id' => "51", "nombre" => "CEUTA"),
	 array ('id' => "13", "nombre" => "CIUDAD REAL"),
	 array ('id' => "14", "nombre" => "CORDOBA"),
	 array ('id' => "15", "nombre" => "CORUÑA, A"),
	 array ('id' => "16", "nombre" => "CUENCA"),
	 array ('id' => "17", "nombre" => "GIRONA"),
	 array ('id' => "18", "nombre" => "GRANADA"),
	 array ('id' => "19", "nombre" => "GUADALAJARA"),
	 array ('id' => "20", "nombre" => "GUIPUZCOA"),
	 array ('id' => "21", "nombre" => "HUELVA"),
	 array ('id' => "22", "nombre" => "HUESCA"),
	 array ('id' => "07", "nombre" => "ILLES BALEARS"),
	 array ('id' => "23", "nombre" => "JAEN"),
	 array ('id' => "24", "nombre" => "LEON"),
	 array ('id' => "25", "nombre" => "LLEIDA"),
	 array ('id' => "27", "nombre" => "LUGO"),
	 array ('id' => "28", "nombre" => "MADRID"),
	 array ('id' => "29", "nombre" => "MALAGA"),
	 array ('id' => "52", "nombre" => "MELILLA"),
	 array ('id' => "30", "nombre" => "MURCIA"),
	 array ('id' => "31", "nombre" => "NAVARRA"),
	 array ('id' => "32", "nombre" => "OURENSE"),
	 array ('id' => "34", "nombre" => "PALENCIA"),
	 array ('id' => "35", "nombre" => "PALMAS, LAS"),
	 array ('id' => "36", "nombre" => "PONTEVEDRA"),
	 array ('id' => "26", "nombre" => "RIOJA, LA"),
	 array ('id' => "37", "nombre" => "SALAMANCA"),
	 array ('id' => "38", "nombre" => "SANTA CRUZ DE TENERIFE"),
	 array ('id' => "40", "nombre" => "SEGOVIA"),
	 array ('id' => "41", "nombre" => "SEVILLA"),
	 array ('id' => "42", "nombre" => "SORIA"),
	 array ('id' => "43", "nombre" => "TARRAGONA"),
	 array ('id' => "44", "nombre" => "TERUEL"),
	 array ('id' => "45", "nombre" => "TOLEDO"),
	 array ('id' => "46", "nombre" => "VALENCIA"),
	 array ('id' => "47", "nombre" => "VALLADOLID"),
	 array ('id' => "48", "nombre" => "VIZCAYA"),
	 array ('id' => "49", "nombre" => "ZAMORA"),
	 array ('id' => "50", "nombre" => "ZARAGOZA")
);
?>

Es un array PHP con los nombres de las provincias y los dos primeros digitos (id) del código postal que le corresponde. No obstante, hay algunas excepciones en esto de los códigos postales. Aquí otra utilidad:

<script type="text/javascript">
/////////////////////////////////////////
//
// CODIGO POSTAL
//

/////////////////////////////////////////
// 
// Función constructora del objeto vector
// Este objeto se usa como matriz asociativa
//

function Vector() 
{
  this["43421"]="Barcelona";
  this["34492"]="Burgos";
  this["01427"]="Burgos";
  this["34815"]="Burgos";
  this["39232"]="Burgos";
  this["01211"]="Burgos";
  this["42142"]="Burgos";
  this["34260"]="Burgos";
  this["26212"]="Burgos";
  this["14449"]="Ciudad Real";
  this["02636"]="Cuenca";
  this["28190"]="Guadalajara";
  this["08717"]="Guadalajara";
  this["08619"]="Lleida";
  this["22583"]="Lleida";
  this["08281"]="Lleida";
  this["22584"]="Lleida";
  this["08697"]="Lleida";
  this["43449"]="Lleida";
  this["08289"]="Lleida";
  this["32151"]="Lugo";
  this["02438"]="Murcia";
  this["04690"]="Murcia";
  this["04647"]="Murcia";
  this["03657"]="Raspay";
  this["50686"]="Navarra";
  this["09471"]="Segovia";
  this["26127"]="Soria";
  this["28310"]="Toledo";
  this["02215"]="Valencia";
  this["42269"]="Zaragoza";
  this["44591"]="Zaragoza";
  this["22808"]="Zaragoza";
  this["42220"]="Zaragoza";
  this["22806"]="Zaragoza";
}

///////////////////////////////////////////////////////
//
// Nombre de provincia como función del CPostal
//

function obtener_provincia_de_cp(codpos){
// A esta func. la llamamos directamente al perder el foco los campos
// cod. postal de cada sección.

  var nodefinido;        // Necesario para comparar con 'undefined'
  var tiponodefinido,tipoexc;
  var cod = new Array(); // Vector que asocia CP con Provincia
  var exc = new Vector();// Vector asociativo para las excepciones
  
  cod[1]="Alava";cod[2]="Albacete";cod[3]="Alicante";
  cod[4]="Almeria";cod[5]="Avila";cod[6]="Badajoz";
  cod[7]="Illes Balears";cod[8]="Barcelona";cod[9]="Burgos";
  cod[10]="Caceres";
  cod[11]="Cadiz";cod[12]="Castellon";cod[13]="Ciudad Real";
  cod[14]="Cordoba";cod[15]="A Coruña";cod[16]="Cuenca";
  cod[17]="Girona";cod[18]="Granada";cod[19]="Guadalajara";
  cod[20]="Guipuzcoa";
  cod[21]="Huelva";cod[22]="Huesca";cod[23]="Jaen";cod[24]="Leon";
  cod[25]="Lleida";cod[26]="La Rioja";cod[27]="Lugo";cod[28]="Madrid";
  cod[29]="Malaga";cod[30]="Murcia";
  cod[31]="Navarra";cod[32]="Ourense";cod[33]="Asturias";cod[34]="Palencia";
  cod[35]="Las Palmas";cod[36]="Pontevedra";cod[37]="Salamanca";
  cod[38]="S.C. Tenerife";cod[39]="Cantabria";cod[40]="Segovia";
  cod[41]="Sevilla";cod[42]="Soria";cod[43]="Tarragona";cod[44]="Teruel";
  cod[45]="Toledo";cod[46]="Valencia";cod[47]="Valladolid";cod[48]="Vizcaya";
  cod[49]="Zamora";cod[50]="Zaragoza";
  cod[51]="Ceuta";cod[52]="Melilla";
  
  if (!isNaN(codpos)){
    if (codpos > 999 && codpos < 53000 && codpos.length == 5){
      var Prov = codpos.substring(0,2);
      if (Prov < 10) Prov=codpos.substring(1,2);
      tiponodefinido= typeof nodefinido;
      tipoexc= typeof exc[codpos];
      if (tipoexc != tiponodefinido) // Si es una excepcion...
        Prov = exc[codpos];           // obtenemos el valor del vector
      else                           // si no lo es...
        Prov = cod[Prov];            // lo pillamos de la tabla cod
      Prov = Prov.toUpperCase();
      return Prov;
    }
  }
  return '';
}
</script>

Y como hoy me siento generoso :P, aquí os coloco un XML con todas las provincias y sus correspondientes localidades.
El Arbol XML tiene la siguiente estructura:

<lista>
	<provincia id="01">
		<nombre><![CDATA[ALAVA]]></nombre>
		<localidades>
			<localidad c="0"><![CDATA[ABERASTURI]]></localidad>
			<localidad c="0"><![CDATA[ABETXUKO]]></localidad>
			<localidad c="0"><![CDATA[ABEZIA]]></localidad>
			<localidad c="0"><![CDATA[ABORNIKANO]]></localidad>
			<localidad c="0"><![CDATA[ACEBEDO]]></localidad>
			<localidad c="0"><![CDATA[ACILU]]></localidad>
			<localidad c="0"><![CDATA[ACOSTA]]></localidad>
			...
			
		</localidades>
	</provincia>
	
	...
	
	<provincia id="29">
		<nombre><![CDATA[MALAGA]]></nombre>
		<localidades>
			<localidad c="0"><![CDATA[RONDA]]></localidad>
			<localidad c="0"><![CDATA[MALAGA]]></localidad>
			...
			
		</localidades>
	</provincia>
</lista>

Podeis descargaros el XML completo en este enlace (zip).
Espero que os sea de ayuda ;)