La versión en inglés de Google Calendar tiene una funcionalidad (Quick Add) que permite añadir eventos describiéndolos tal y como lo haríamos a otra persona (ejem... anglosajona): "Lunch at new restaurant Friday at 1pm".


Bastante cool... pero no está disponible en castellano. Podríamos quejarnos, pero en la Web 2.0 (signifique lo que signifique el "2.0"...) sucede a menudo que en lugar de eso puedes hacer las cosas tú mismo. En este post incluímos un pequeño ejemplo de Quick Add que entiende (un poco de) castellano, como muestra de lo que cualquiera puede hacer con el API de Google Calendar


El API de Calendar esta basado en el protocolo GData para leer y escribir datos en formato XML a través de peticiones HTTP. Esto permite tratar los datos en una gran cantidad de lenguajes de programación. Para este ejemplo, usaremos la librería de Javascript, que ofrece algunas funciones útiles.


Podemos obtener los eventos en un calendario, modificarlos, borrarlos, o añadir eventos nuevos. Para un ejemplo de cómo obtener los eventos de un calendario, puedes ver el código de esta página, que obtiene los eventos de un calendario público. También podemos obtener los de un calendario privado, con la correspondiente autorización. De hecho este post usa prácticamente el mismo código para mostrarte los eventos de tu calendario.


Si haces click en 'Entrar' a continuación, deberás hacer login en tu cuenta de Google (si no lo has hecho aún) y permitir el acceso a tu calendario a esta página. Entonces se te mostrarán tus próximos eventos en el cuadro de abajo. Además, podrás crear nuevos eventos con el cuadro de texto que aparecerá.


Siendo sólo una muestra, tiene una funcionalidad bastante limitada, y sólo entiende eventos de la forma QUÉ [en DÓNDE] CUÁNDO. Ejemplos:

Puedes probar con frases similares en el cuadro de texto. (Sólo entiende eventos para hoy, y el formato de hora debe ser HH:MM con la hora de 0 a 23)

Estos son buenos puntos de partida para empezar a programar con el API de Google Calendar: Google Calendar API: Home, Documentation, Samples, Developer's guide: Javascript, Javascript client library API reference.

Y ahora lo siento pero debo irme. Al estar probando el código se me ha llenado el calendario de asuntos que tengo que atender...

.
  • Reescribe las funciones del mapa que se suelen asociar con una función de carga (load function). Como el mapa se carga de forma síncrona antes de ejecutar el código del mapplet, no es necesario encapsular las funciones del mapa dentro de un gestor de carga. Si el mapplet se estructura según lo indicado, todos los elementos de la página se cargarán antes de que se ejecute el script; no deberías tener problemas para desprenderte de la función de carga que envuelve tu código.
  • 2. Utilizar el mapa común

    • Añade en la etiqueta de modo que el gadget pueda acceder a la version específica de mapplet del API de Maps.
    • Elimina la etiqueta script que contiene el script responsable de cargar el API de Maps normal. El Gadget XML de Google carga ahora la versión Mapplet del API de Maps gracias al sharedmap.
    • Elimina el div que habías utilizado anteriormente para cargar tu mapa. Como estás compartiendo el mapa con otros mapplets, no se necesita ningún elemento div.
    • Elimina el argumento del constructor GMap2. No es necesario decirle al constructor dónde cargar el mapa, puesto que el mapa común ya está cargado.
    • Elimina el GBrowserIsCompatible y comprueba si lo estás utilizando. Si un usuario ha cargado tu mapplet en el mapa, puedes dar por hecho que están utilizando un navegador compatible con Google Maps.
    Así, el mashup de maps original sería:


    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>

    <meta http-equiv="content-type" content="text/html;
    charset=utf-8"/>

    <title>Google Maps AJAX + mySQL/PHP
    Example</title>


    <script src="http://maps.google.com/maps?file=api&v=2&key=abc123"
    type="text/javascript"></script>

    <script type="text/javascript">

    //<![CDATA[

    function load() {


    if (GBrowserIsCompatible()) {

    var map = new GMap2(id="maparg">document.getElementById("map"));
    map.setCenter(new GLatLng(37, -122));

    }


    }
    //]]>
    </script>

    </head>
    <body onload="load()" onunload="GUnload()">


    <h2> My Really Simple Map </h2>

    <div id="map" style="width: 500px; height:
    300px"></div>

    </body>

    </html>


    Y el mapplet:

    <?xml version="1.0" encoding="UTF-8"?>

    <Module>
    <ModulePrefs title="My Simple Map"
    description="A converted maps api example"
    author="Your name"
    author_email="your-email@google.com"
    height="150">

    <Require feature="sharedmap"/>


    </ModulePrefs>

    <Content type="html">
    <![CDATA[


    <h2>My Simple Map</h2>

    <script>
    var map = new GMap2();
    map.setCenter(new GLatLng(37, -122));
    </script>


    ]]>
    </Content>
    </Module>


    Funciones asíncronas del mapa

    Como ahora estamos utilizando el mapa común, algunas de las llamadas al mapa pidiendo información son asíncronas. Esto significa que el valor devuelto no se devuelve al código instantáneamente, sino que pasa por una función de callback. Si actualmente utilizas una función que ahora es asíncrona en mapplets, solo tienes que modificar el código para que todo lo que ocurra después de esa función (y dependiera de su resultado) ahora esté encapsulado dentro del parámetro de la función de callback.

    Las funciones afectadas y sus versiones asíncronas aparecen a continuación:

    GMap
    getMapTypes()getMapTypesAsync(callback)
    getCurrentMapType()getCurrentMapTypeAsync(callback)
    isLoaded()isLoadedAsync(callback)
    getCenter()getCenterAsync(callback)
    getBounds()getBoundsAsync(callback)
    getBoundsZoomLevel(bounds)getBoundsZoomLevelAsync(bounds, callback)
    getSize()getSizeAsync(callback)
    getZoom()getZoomAsync(callback)
    getInfoWindow()getInfoWindowAsync(callback)
    fromLatLngToDivPixel(latlng)fromLatLngToDivPixelAsync(latlng, callback)
    fromDivPixelToLatLng(pixel)fromDivPixelToLatLngAsync(pixel, callback)
    fromContainerPixelToLatLng(pixel)fromContainerPixelToLatLngAsync(pixel, callback)
    GMarker:
    getIcon()getIconAsync(callback)
    getPoint()getPointAsync(callback)
    isHidden()isHiddenAsync(callback)
    GPolygon/GPolyline:
    getVertexCount()getVertexCountAsync(callback)
    getVertex(index)getVertexAsync(index, callback)
    GClientGeocoder
    getLatLngAsync(address, callback)getLatLng(address, callback)
    getLocationsAsync(address, callback)getLocationsAsync(address, callback)

    Este es un ejemplo de la documentación que utiliza map.getCenter()y que tiene que modificarse para utilizar la versión asíncrona de la función.

    var map = new GMap2(document.getElementById("map"));
    GEvent.addListener(map, "moveend", function() {
    var center = map.getCenter();
    document.getElementById("message").innerHTML = center.toString();
    });
    map.setCenter(new GLatLng(37.4419, -122.1419), 13);

    En la version mapplet, sustituimos getCenter() por getCenterAsync(), y ponemos el código que se supone que debería ejecutarse después dentro de una función de callback.

    var map = new GMap2();
    GEvent.addListener(map, "moveend", function() {
    map.getCenterAsync( function(center) {
    document.getElementById("message").innerHTML = center.toString();
    });
    });
    map.setCenter(new GLatLng(37.4419, -122.1419), 13);

    Cómo hacer llamadas AJAX “al estilo mapplet”

    Actualmente, el API de mapplets no soporta los métodos del API de Maps para hacer llamadas AJAX (GXml, GXmlHttp, GDownloadUrl). Pero no pasa nada, porque el API de gadgets ya tiene funciones que te ayudan a obtener contenido remoto en tu aplicación:

    • _IG_FetchContent(url, func)
    • _IG_FetchXmlContent(url, func)
    • _IG_FetchFeedAsJSON(url, func, num_entries, get_summaries)
    Las funciones de los gadgets de Google difieren ligeramente en lo relativo al XML que aceptan y a su conducta de almacenamiento en cache, así que es recomendable leer las diferencias. También hay más información en la documentación de los gadgets de Google.

    Los más probable es que la aplicación de mapas utilice GDownloadUrl para descargar un archivo XML, como en este ejemplo:


    GDownloadUrl("markers.xml", function(data) {
    var xml = GXml.parse(data);
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
    var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
    parseFloat(markers[i].getAttribute("lng")));
    map.addOverlay(new GMarker(point));
    }
    });


    En la version mapplet, sustituimos GDownloadUrl por _IG_FetchXmlContent que utiliza los mismos parámetros pero devuelve un documento XML analizado en el callback, acabando con la necesidad de analizar el XML.


    _IG_FetchXmlContent("markers.xml", function(data) {
    var markers = data.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
    var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
    parseFloat(markers[i].getAttribute("lng")));
    map.addOverlay(new GMarker(point));
    }
    });

    Por último, es importante tener en cuenta que hay elementos que no se pueden modificar en el mapa principal, para que la interfaz del usuario sea igual en todos los mapplets que comparten el mapa común. Comprueba que no tienes ninguno de los elementos no permitidos y prueba tu mapplet en todos los navegadores Lo único que queda ahora es enviar el mapplet al directorio de contenidos. ¡Esperamos vuestras contribuciones!