Cross Domain Web
Mashups with JQuery
and Google App Engine




Andy McKay. Clearwind Consulting
http://clearwind.ca
Also known as
A bunch of cool buzz words to try and describe
    some of the stuff I’m doing these days
   and get me in to talk at cool conferences
Cross Domain
   JQuery
 App Engine
Cross Domain
   JQuery
 App Engine
mashup
“a web page or application that combines data
  from two or more external online sources”
reusable web applications
that aren't SOAP and WSDL

"The three chief virtues of a programmer are: Laziness,
         Impatience and Hubris”. Larry Wall
back in time...
Zope 2
Plone
 Rails
Django
rewriting things constantly
 is good for billable hours
small web applications
    returning xml
Ajax


 browser: rails.site.ca


                                 server: another.ca

browser: django.site.ca
there's a problem
Single origin policy
browser: clearwind.ca                           server: some.other.ca

The same origin policy prevents document or script loaded from one origin from getting
or setting properties of a document from a different origin.
-- From http://www.mozilla.org/projects/security/components/same-origin.html
1. proxy


browser: clearwind.ca   server: clearwind.ca   server: some.other.ca
2. hacks

  flash
 iframe
document
  script
3. JSONP

JavaScript Object Notation
       with Padding
Example: json-time
                 By Simon Willison
           http://json-time.appspot.com/
http://github.com/simonw/json-time/tree/master
JSON
{
    "tz": "America/Chicago",
    "hour": 3,
    "datetime": "Tue, 19 May 2009 03:06:50 -0500",
    "second": 50,
    "error": false,
    "minute": 6
}
JSONP

process_time({
  "tz": "America/Chicago",
  "hour": 3,
  "datetime": "Tue, 19 May 2009 03:09:09 -0500",
  "second": 9,
  "error": false,
  "minute": 9
})
Cross Domain
   JQuery
 App Engine
JQuery for json-time


var url = "http://json-time.appspot.com/timezones.json?"

$.getJSON(url + "callback=?",
        function (json) {
          ...
        });
JSON time demo
Complete JSON time demo
$(document).ready(function() {
    var url = "http://json-time.appspot.com";

      function showTime(data) {
          $.getJSON(url + "/time.json?tz=" + $("#zones").val() + '&callback=?',
              function (json){
                  $("#zones-msg").text('The time is now ' + json["datetime"] + '.');
              });
      };

      $.getJSON(url + "/timezones.json?callback=?",
          function (json) {
              var zones = $("#zones");
              for (var k = 0; k < json.length; k++) {
                  zones.append("<option>" + json[k] + "</option>");
              };
              zones.bind("change", showTime)
          });
});
Cross Domain
   JQuery
 App Engine
Easiest deployment
  Best scalability
  Minimal effort
Not straight Python
Has it's limitations and quirks
And it's free
Example Mashup
  The coolest technology of 2006
          Google Maps
The most hyped technology of 2009
               Twitter
Twitter messages with a map
 by hash tag eg: #owv2009
Step 1:
Assign hash tag to location
geohashtag.appspot.com




browser: geohashtag.appspot.com   server: geohashtag.appspot.com
Model

from google.appengine.ext import db

class Tag(db.Model):
    name = db.StringProperty(required=True)
    geostring = db.StringProperty(required=True)
Issue
You cannot do an inequality test on two fields in one query.
                     Or use GeoPt.

               GeoHash solves this problem:
           http://en.wikipedia.org/wiki/Geohash
JSON

     tag.json (returns location for a tag)
bounds.json (returns all the tags in a rectangle)
Geohashtag demo
Step 2:
Parse RSS into JSONP
atomtojsonp.appspot.com




browser: atomtojsonp.appspot.com                 server: search.twitter.com
                         server: atomtojsonp.appspot.com
Proxy?
    Because twitter doesn't have JSON export
Other services like Google RSS or Yahoo YQL have
                     problems

  But checkout: http://developer.yahoo.com/yql/
   and http://code.google.com/apis/ajaxfeeds/
No Model

Quite common for
  App Engine
Just feedparser
                  http://www.feedparser.org/


class JSONHandler(webapp.RequestHandler):
    def get(self):
        url = self.request.get("url")
        data = feedparser.parse(url)
        if self.request.get("callback"):
            data = "%s(%s)" % (self.request.get("callback"), data)
        self.response.out.write(data)
JSON

twitter.json (smaller twitter version for a search term)
         atom.json (a whole atom file for a url)
Atomtwojsonp demo
Step 3:
Mash it up
geojsontweet.appspot.com


browser: geojsontweet.appspot.com   server: maps.google.com




browser: geojsontweet.appspot.com
geojsontweet.appspot.com


browser: geojsontweet.appspot.com     server: maps.google.com




browser: geojsontweet.appspot.com   server: geohashtag.appspot.com




browser: geojsontweet.appspot.com
geojsontweet.appspot.com


browser: geojsontweet.appspot.com                server: maps.google.com




browser: geojsontweet.appspot.com              server: geohashtag.appspot.com




browser: geojsontweet.appspot.com                server: search.twitter.com
                         server: atomtojsonp.appspot.com
No Model
In fact, completely static HTML
  (with JS, no server side code)
Some Javascript
function move() {
        var bounds = map.getBounds();
        var sw = bounds.getSouthWest();
        var ne = bounds.getNorthEast();

       var url = map_details.tags_domain + '/bounds.json?nelat=';
       url += ne.lat() + '&nelon=' + ne.lng();
       url += '&swlon=' + sw.lng() + '&swlat=' + sw.lat() + '&callback=?'

       if (map_details.last_url != url) {
           map_details.last_url = url
           $.getJSON(url,
               function(json) {
                   if (json) {
                       for (var k = 0; k < json.length; k++) {
                           ...
Some more Javascript

function twitter() {
    var tag = null;
    for (var obj in tags) {
        var url = map_details.atom_domain + '/twitter.json?tag=' + obj +
'&callback=?'
        $.getJSON(url,
            function(json) {
                var tweet = null;
                for (var k = 0; k < json.length; k++) {
                     ....
Slideshow
     http://flowplayer.org/tools/scrollable.html


$("#tweets-" + tweet["tag"]).parent().scrollable({
    interval: 4000,
    loop: true,
    speed: 600,
    onBeforeSeek: function() {
        this.getItems().fadeTo(300, 0.2);	 	
    },
    onSeek: function() {
        this.getItems().fadeTo(300, 1);
    }
});
Geojsontweet demo
Serious issues
Trust
You are executing someone else's JavaScript
     in your site. Better be trustworthy.
Single points of failure?
Single points of failure?
Enterprise
Internal servers?
Questions?
Code: http://svn.clearwind.ca/public/projects/presentations
                 Email: andy@clearwind.ca

huhu