JQuery Mobile Project

Finally, JQuery teams embark into Mobile JS Framework. On the 11 Aug 10, John Resig announced the JQuery Mobile Project.  http://jquerymobile.com/

JQuery Mobile

The jQuery project is really excited to announce the work that we’ve been doing to bring jQuery to mobile devices. Not only is the core jQuery library being improved to work across all of the major mobile platforms, but we’re also working to release a complete, unified, mobile UI framework

I have been fan of JQuery and look forward to the Mobile version. The framework will work on all popular smarphone and tablet platforms such as Android, iOS, BlackBerry, Windows Phone, Palm WebOS, Symbian, MeeGo and Bada.

So far, there are a few others who are in beta now for example Sencha Touch and YUI 3.2. Let’s see which one will be the lightest and fastest.

Progressive Enhancement using EnhanceJS

The first time I read about designing with progressive enhancement, I was a bit confuse. So, I did a bit of digging around and I find it interesting. You can call Progressive Enhancement t a coding methodology and it is simple in theory: start with the basic and standard HTML only pages to ensure that any browser and device are able to render it in a usable way. Then, when the browser and device understand the style and script, enhance the page by adding the style and script layer.

The idea address concern from the 2 camps, the web developer and web designer. The designer wants to put the latest styles and technology to beautify the page while the developers concern about cross-browser and cross-device compatibility. By testing the browser capabilities, we can target which enhanced experience to layer into the page. One thing I learnt about progressive enhancement is you have think of the site in layer of enhancement, you must structure styles and script to ensure they are loaded proper order. That is the challenging part. 🙂

 The idea to progressively enhance the site is from the Filament Group and they developed a framework for testing those browser capabilities. The library is EnhanceJS.

EnhanceJS is a new JavaScript framework (a single 2.5kb JavaScript file once minified/gzipped) that automates a series of browser tests to ensure that advanced CSS and JavaScript features will render properly before they’re loaded to the page, enabling you to build advanced, modern websites without introducing accessibility problems for people on browsers that aren’t capable of supporting all advanced features. It’s designed to be easily integrated into a standard progressive enhancement workflow: just construct the page using standard, functional HTML, and reference any advanced CSS and JavaScript files using EnhanceJS to ensure they’re only delivered to browsers capable of understanding them.EnhanceJS is a new JavaScript framework (a single 2.5kb JavaScript file once minified/gzipped) that automates a series of browser tests to ensure that advanced CSS and JavaScript features will render properly before they’re loaded to the page, enabling you to build advanced, modern websites without introducing accessibility problems for people on browsers that aren’t capable of supporting all advanced features. It’s designed to be easily integrated into a standard progressive enhancement workflow: just construct the page using standard, functional HTML, and reference any advanced CSS and JavaScript files using EnhanceJS to ensure they’re only delivered to browsers capable of understanding them.

Let’s see how the concept work in code. In the script below, you see how the test work. If you pass the test you will get the “enhanced” styles and scripts. You can even have conditional test for IE. You no longer need to write those “complex” script find out the user agent and browser ‘s behaviors. It is clearner also.

<script type="text/javascript" src="enhance.js"></script> 
<script type="text/javascript">
 enhance({
  loadStyles: [
   'css/enhancements.css',
   {href: 'css/print.css', media: 'print'},
   {href: 'css/ie6.css', iecondition: 6}
  ], 
  loadScripts: [
   'js/jquery.min.js',
   'js/enhancements.js'
  ]
 });  
</script>

The other useful feature of the framework is it is extensible. You can add your own browser capability test. Btw, EnhanceJS does not test HTML5 features this is where the “add test” come handy. You can integrate EnhanceJS and Modernizr or write your own test for that. A simple example below;

<html>
<head>
  <title>
    2D drawing with Canvas
  </title>
  <script type="text/javascript" src="js/modernizr-1.5.min.js"></script>
  <script type="text/javascript" src="js/enhance.min.js"></script>
 <!-- Application JS -->
 <script type="text/javascript">
 enhance({
  loadScripts: [ 'js/jquery-1.4.2.min.js', 'js/enhancements.js' ],
  addTests: {
   canvasSupport: function() {
    if (Modernizr.canvas) return true;
    else return false;
   }
  }
 });
 </script>

</head>
<body>
 Using EnhanceJS to check canvas. <br/>
 <div id="canvasPanel"></div>
</body>
</html> 

//source for enhancements.js
function draw() {
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  ctx.fillStyle = "rgb(200,0,0)";
  ctx.fillRect (10, 10, 55, 50);

  ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
  ctx.fillRect (30, 30, 55, 50);
}

$(document).ready(function(){
 $('#canvasPanel').html('<canvas id="canvas" width="300" height="300"></canvas>');

 draw();
});
// end document ready

More info on the site:

Detects Support for HTML5 and CSS3

There are lots of new and cool features in HTML5 such as canvas, geolocation, etc. Unfortunetely not all browsers support the features. So, how do we detects whether or not a browser supports a particular feature? Here are four basic techniques I extracted from diveintohtml5.org:

1. Check if a certain property exists on a global object (such as window or navigator).


function testGeolocation() {

    return !!navigator.geolocation;

}

2. Create an element, then check if a certain property exists on that element.


function testCanvas() {

    return !!document.createElement('canvas').getContext;

}

3. Create an element, check  if a certain method exists on that element, then call the method and check the value it returns.

function testVideo() { 
 if (!document.createElement('video').canPlayType) {
   return false;
 }
  var v = document.createElement("video");
  return v.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
}

4. Create an element, set a property to a certain value, then check if the property has retained its value.

   var i = document.createElement("input");
   i.setAttribute("type", "datetime");
   return i.type !== "datetime";

Of course there is the 5th way, which is to use a HTML5 detection library. it is called Modernizr. It is an open source and MIT-licensed.

Modernizr is a small and simple JavaScript library that helps you take advantage of emerging web technologies (CSS3, HTML 5) while still maintaining a fine level of control over older browsers that may not yet support these new technologies.

To use it, simply include the Modernizr script into your page. You can download the script from http://www.modernizr.com/

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="modernizr.min.js"></script>
</head>
<body>
  ...
</body>
</html>

Looking back at the examples from the 4 basic techniques above, here is how it looks like using Modernizr

if (Modernizr.geolocation){
  navigator.geolocation.getCurrentPosition(function(position) {
    setUserLatandLong(position.coords.latitude,position.coords.longitude);
  }); 
} else {
 // Sorry, your browser is very old.
}

There are more example on the documentation site.

10 Informative Infographics

Complex and huge amount of data are hard to comprehend and navigate, especially when they are presented in words or text. Presenting it in words or text is just plain boring and turn off the audience. Information graphics or Infographics is a visual representation of those data. It is an excellent visual representation of data, it is easier to comprehend and the graphics helps us relate with the data. It does add some “emotional aspect” also. This is an excellent way to communicate clearly and it is self explanatory.

Information graphics or infographics are graphic visual representations of information, data or knowledge. These graphics present complex information quickly and clearly – Wikipedia

In order to appreciate them, here are some of the creative, informative and well-designed inforgraphics I have found.

1. World Cup 2010 Calendar – http://www.marca.com/deporte/futbol/mundial/sudafrica-2010/calendario-english.html

2. Revisit is a real-time visualization of the latest twitter messages (tweets) around a specific topic. – http://moritz.stefaner.eu/projects/revisit/

3. It’s 140 most influential Twitter users – http://informationarchitects.jp/c140/

4. The Evolution of Privacy on Facebook – http://mattmckeon.com/facebook-privacy/

5. A Visual History of the American Presidency – http://timeplots.com/potus/

6. An infographic résumé – http://joaocorreia.pt/infographics/infographic-resume/. A very interesting way of presenting resume, this is good for job in design industry.

7. Japan, the Strange Country – by  Kenichi Tanaka http://www.kenichi-design.com/. This one is a video and in Japanese. Unfortunetely the English version was deleted. But it is still interesting too watch.

Japan – The Strange Country (Japanese ver.) from Kenichi on Vimeo.

8. ASK KEN™ is sort of a Node-Link diagram that allows to visually navigate through interconnected topics. – http://askken.heroku.com/ . Btw, this site only support FF, Safari and Chrome.

9. Every Country’s #1 at Something – http://www.informationisbeautiful.net/visualizations/because-every-country-is-the-best-at-something/

10. An information graphic for AOL Autos comparing Teen Drivers to Senior Drivers, visualizing various statistics on who are the safer drivers. http://gavinpotenza.com/old-young-drivers/

Web Scraping using C#

Yesterday, I was looking at the SBS Transit website and looking for “easy” way to get the bus arrival time. Yes, the site has its own mobile version but I thought I can do more if I have the raw data. Unfortunetely the site does not provide any web services. After searching for awhile, found someone (Deepak Sarda) that created a simple JSON API to get the arrival time via http://sbsnextbus.appspot.com/. What he did was web scraping the SBS Iris site run it on GAE.

Web scraping, sound old, messy and tidious. In most cases, it is hard to keep up with the changes and your code will break if the site change layout or content often. Unfortunately, not everyone make the data readily available via web services or json API. I created a simple apps to test the API – http://bit.ly/caXufL – Curious, I decided to work on my own web scraping using c#.

Before you start web scraping, it is good to understand the site behaviour. You can use tools like HttpFox (FF) or HttpWatch (IE) to simulate and find out whether or not the sites uses cookies. For form posting, You need to know all the input parameters. Another special case is ASP.NET site, You need to maintan the ViewState. I have 2 examples below, 1) web scraping web content and 2) posting data.

1. Extracting web content – The simplest way to harvest those HTML is to use HttWebRequest.

    CookieContainer cookies = new CookieContainer();
    string baseUrl = @"web site url";
    System.Net.HttpWebRequest httpwr = (HttpWebRequest)WebRequest.Create(baseUrl);
    httpwr.Method = "GET";
    httpwr.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8";
    httpwr.ContentType = "text/html";
    httpwr.CookieContainer = cookies;

    HttpWebResponse res = (HttpWebResponse)httpwr.GetResponse();
    res.Cookies = httpwr.CookieContainer.GetCookies(httpwr.RequestUri);
    string resStr = new System.IO.StreamReader(res.GetResponseStream()).ReadToEnd();
  Console.WriteLine(resStr);

2. Posting data

    string postData = String.Format("__EVENTTARGET=&__EVENTARGUMENT=&param0={0}&param1={1}&param2={2}", "input1", "input2","input3");
    byte[] data = encoding.GetBytes(postData);

    httpwr = (HttpWebRequest)WebRequest.Create(url);
    httpwr.Method = "POST";
    httpwr.AllowAutoRedirect = true;  // To handle redirection. Set to false if it is not required.
    httpwr.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8";
    httpwr.ContentType = "application/x-www-form-urlencoded";
    httpwr.CookieContainer = cookies;
    httpwr.ContentLength = data.Length;
    //Post content
    using (var stream = httpwr.GetRequestStream())
    {
        stream.Write(data, 0, data.Length);
    }
    res = (HttpWebResponse)httpwr.GetResponse();
    using (var sr = new StreamReader(res.GetResponseStream()))
    {
        resStr = sr.ReadToEnd();
    }
  Console.WriteLine(resStr);

You can then extend further by exposing the harvested data via web services using the WebMethod in ASP.NET.

  [WebMethod()]
  public static Data[] GetData(string input)
  {
    // web scraping the site
    // parse the content
    //store in db or memcache
    return result.ToArray();
  }

In some cases, web scaping is not as straight forward as getting and posting data. Some site maintain specific flow base on specific parameter. In this case, you may need to combine a few call (combination of 1 and 2) to get the result you want. Once the HTML content is harvested, you will then need to parse it. I found a good parser for .NET, it is call HTMLAgilityPack. It supports XPATH or XSLT and Linq, and easy to use.

 HtmlDocument doc = new HtmlDocument();
 doc.Load(responseString);
 foreach(HtmlNode form in doc.DocumentElement.SelectNodes("//form[@action"])
 {
    HtmlAttribute att = form["action"];
    Console.WriteLine(att.Value);
 }

Hello HTML 5

Since the “fight” between Apple and Adobe on Flash, HTML5 technology has recently into the spotlight. It was then follow by Apple launched its HTML5 showcase site, then Google announced its HTML5 Rocks. Although HTML5 is still in working draft (http://www.w3.org/TR/html5/) and expects the specification to reach the Candidate Recommendation stage during 2012. Most of the browsers are prepared for it and HTML5 ready, e.g. 
  • Firefox
  • Google Chrome
  • Opera
  • Apple Safari

Microsoft IE is currently a bit late but they are catching up with IE9. You can follow the development here http://blogs.msdn.com/b/ie/. For the IE fan, to browse HTML5 sites you will need 

What is so cool about HTML5? Here are some of the new features: 

  • The canvas element for immediate mode 2D drawing.
  • Timed media playback
  • Offline storage database (offline web applications).
  • Document editing
  • Geolocation
  • and more…

For all of us to appreciate all these features we must see it in action, right. Seeing is believing, here is the list of 5 sites and gallery you must explore (in no particular order :)): 

 

  

Apple HTML5 Showcase

 

  

HTML5Rocks

 

  

HTML5 Gallery

 

  • HTML5 Demos – HTML5 Demos offer a good overview of how HTML5 is changing the landscape and its capabilities.

  

HTML5 Demo

 

Checkout those links and post your opinion.

Nearby Tweet (Makeover)

After spending my weekend reading Sencha Touch, I decided to do a bit of makeover for my “Nearby Tweet”. Sencha Touch kind of save me the time from learning the native mobile SDK like iOS or Andoid. It is using standards such as JavaScript, HTML 5 and CSS3, all I need to learn is the framework.

The previous version has a very important limitation which no geolocation, it is hardcoded to Singapore. Using the Geolocation feature in HTML 5, the application is now able to locate the user and mark the nearby tweets into the map. Another improvement is the use of “Tab Panel” to show both map and the tweets. Here is the screenshots:

So , how is it done?

Step 1: Include Sencha Touch CSS & JavaScript, Google Map API and own CSS & JavaScript.

<!DOCTYPE html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <title>Nearby Tweets Mobile</title>
 <link rel="stylesheet" href="css/ext-touch.css" type="text/css">
 <link rel="stylesheet" href="css/NearByTweetsMobile.css" type="text/css">
 <script type="text/javascript" src="<a href="http://maps.google.com/maps/api/js?sensor=true">http://maps.google.com/maps/api/js?sensor=true</a>"> </script>
 <script type="text/javascript" src="js/ext-touch.js"> </script>
 <script type="text/javascript" src="js/NearByTweetsMobile.js"> </script>
</head>
<body> </body>
</html>

Step 2: Implement the JavaScript for loading the UI, getting the Tweets and marking it on the map. There no change to the code that add marker and get location from previous implmentation.

Ext.setup({
    icon: 'icon.png',
    glossOnIcon: false,
    onReady: function() {
      // nbTweets - tweet list. Using Template to generate the html.
        var nbTweets= new Ext.Component({
            title: 'Nearby Tweets',
            scroll: 'vertical',
            tpl: [
                '<tpl for=".">',
                    '<div>',
                            '<div><img src="{profile_image_url}" /></div>',
                            '<div>',
                                '<h2>{from_user}</h2>',
                                '<p>{text}</p>',
                                '<p>{location}</p>',
                            '</div>',
                    '</div>',
                '</tpl>'
            ]
        });

        var map = new Ext.Map({
            title: 'Map',
            getLocation: true,
            mapOptions: {
                zoom: 12,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            }
        });
       
    var geocoder = new google.maps.Geocoder();

    // Create tab panel for the map and tweet list timeline
        var panel = new Ext.TabPanel({
            fullscreen: true,
            animation: 'slide',
        ui: 'light',
            items: [map, nbTweets]
        });

    // handler for refresh button    
        var refresh = function() {
            var coords = map.geo.coords; // get user geolocation

            Ext.util.JSONP.request({
                url: 'http://search.twitter.com/search.json',
                callbackKey: 'callback',
                params: {
                    geocode: coords.latitude + ',' + coords.longitude + ',' + '10km',
                    rpp: 30
                },
                callback: function(data) {
                    data = data.results;

                    // Update the tweets in nbTweets
                    nbTweets.update(data);
                    // Add points to the map
                    for (var i = 0, ln = data.length; i < ln; i++) {
                        var tweet = data[i];
                        getTweetLocation(map, geocoder, tweet);
                    }
                }
            });
        };

        map.geo.on('update', refresh);

        var tabBar = panel.getTabBar();
        tabBar.addDocked({
            xtype: 'button',
            ui: 'mask',
            iconCls: 'refresh',
            dock: 'right',
            stretch: false,
            align: 'center',
            handler: refresh
        });

    }
});

// These are all Google Maps APIs
function getTweetLocation(map, geocoder, tweet) {
 // insert the code to get tweet location either from the geotag or tweet.location
    if (tweet.geo && tweet.geo.coordinates) {
        var position = new google.maps.LatLng(tweet.geo.coordinates[0], tweet.geo.coordinates[1]);
    addMarker(map, position, tweet);
    } else {
    var geocode = tweet.location.split(": ",2);
    var addr = geocode[1];
    if (addr == undefined) addr = tweet.location;
      if (geocoder) {
        geocoder.geocode( { 'address': addr }, function(results, status) {
          if (status == google.maps.GeocoderStatus.OK) {
           addMarker(map, results[0].geometry.location, tweet);
          } else {
            //alert("Geocode was not successful for the following reason: " + status);
          }
        });
      }
    } // end if tweet.geo
} // end addMarker
       
function addMarker(map, position, tweet) {
 // insert the code to add marker to map.
} // end addMarker

So far, I have tested in iPhone Safari (on iOS4) and it works fine. Not sure how it performs in Android yet. One thing to note is the mobile browser must support HTML 5. 🙂 If you try the links below on Android, drop me a comment whether or not it works and what Android version you are using.

Nearby Tweets Mobile: http://www.wswijaya.com/prototype/NearByTweetsMobile.php

Sencha Touch Version: 0.91 (public beta)

Sencha = Ext JS + jQTouch + Raphaël

Sencha here is not refering to the name of a popular Japanese green tea. It is a combine forces between Ext JS with the jQTouch and Raphaël projects, changing the company name to Sencha. I guess coffee (“java”)  is out of trend already and now we moving to tea. 🙂  If you are not familiar with Ext JS, it is one of the popular framework for building rich web application. Recently the team announced the release HTML 5 framework for Mobile name Sencha Touch. is it the end of native mobile application? up to you to decide after you try out 🙂

Sencha Touch, the first HTML5 framework for mobile devices. We think it’s the first cross-platform framework that builds web apps that make sense for mobile devices. It comes with a comprehensive UI widget library, complete touch event management with CSS transitions and an extensive data package.

Some of the features highlight are:

  • Touch Event – Bind non-standard touch events to your elements like tap, doubletap, swipe, pinch, and rotate to create amazing interactions.
  • W3C Standards – Sencha Touch is built with web standard HTML5, CSS3, and Javascript, making it a very flexible mobile app framework. (ready for Android and Apple iOS devices)
  • Animation – Animate between views using one of our many predefined animations, with loads of configuration options.
  • Geolocation & Maps – Discover a user’s location and display nearby points of interest in our Google Maps component.
  • Sencha Touch UI – Rich UI library (AJAX, Icons, Audio, Nested Lists, Video, Sortable Lists, Carousel, Overlay, Picker, Toolbars, Drag & Drop, Geolocation)

HTML 5 is on the rise and the development has been on hyper speed, recently Apple developed the HTML 5 gallery to counter Flash and then follow by Google with its own gallery. With the development of this framework it opens up a bigger possibilities for developers. Some of the advatanges i can think of are:

  • Developer does not have to learn a specific language such as Objective-C. It is web standard, HTML 5, CSS3, JavaScript.
  • Develop once and run on any mobile. As compared to the native, it is accessible from any mobile devices (currently Android & iPhone) and it can be deployed with your other server application.
  • Code reuse. Increase reusability as it can share the same component as your other web application.

So what is the down side?

  • Slower learning curve. It is new framework and contain a large number of API. It will take sometime to understand. I try to browse around but not much of example except the one from Sencha Touch Example. But if you are good with JavaScript, I am sure picking up new framework is an easy job 🙂
  • Limited or no access to OS features (e.g. contacts, camera, etc) and peripheral devices.

I am currently using the framework to enhance my “Near By Tweets” and give the application a makeover. I notice one bug when I was trying to read XML data. No sure whether or not it is bug or just me. 🙂 Anyway, it is still in beta stage.  If you are wondering what is the licensing like, read this

The initial beta is under a GPLv3 + FLOSS license. We’d like to give open source folks the benefit before we introduce a commercial trial license. And we’d like to take the opportunity to emphasize something that many people miss: that we have Free and Open Source exceptions as part of our GPLv3 license. So if you want to, you can include Sencha Touch in your Apache and OSI approved licensed projects without triggering the GPL’ing of your project.

Hope this trigger your curiousity to try out. The first public beta released is available for download at http://www.sencha.com/products/touch/download.php?dl=publicbeta091.

Nearby Tweet (updated)

Last December I created a simple “Nearby Tweet” using Google Maps API. It was based on version 2. Since Google Maps API v3 is official, I decided to migrate the code. In the latest version, one of the noticable change for developer is the removal of the Google Maps Key. Version 3 is designed to be faster and target both desktop and mobile devices.  btw, version 2 is deprecated and if you still using it, remember to migrate. Finally found time to look into the old codes. I did some clean up, migrate to v3 and make sure it support iPhone Safari.

Let’s start with the changes:

Change 1: JavaScript URL. Note: applications that determine the user’s location via sensor must pass sensor=trye when loading the Maps API JavaScript.

Change 2: Additional <meta> tag for iPhone device. The setting specifies that this map should be displayed full-screen and should not be resizable by the user.

<html>
<head>
 <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
 <script language=JavaScript src="js/jquery-1.3.2.min.js" type=text/javascript></script>
 <script type="text/javascript" src=<a href="http://maps.google.com/maps/api/js?sensor=false">http://maps.google.com/maps/api/js?sensor=false</a>></script>
</head>
<body>

Change 3: Add new function to detect browser (for Mobile)

function detectBrowser() {
  var useragent = navigator.userAgent;
  var mapdiv = document.getElementById("map_canvas");
   
  if (useragent.indexOf('iPhone') != -1 || useragent.indexOf('Android') != -1 ) {
    mapdiv.style.width = '100%';
    mapdiv.style.height = '100%';
  } else {
    mapdiv.style.width = '600px';
    mapdiv.style.height = '800px';
  }
}

Change 4: Updated the “Nearby Tweet” code to call version 3 API.

 function initialize() {     
  geocoder = new google.maps.Geocoder();
  var latlng = new google.maps.LatLng(1.2915, 103.8492);
    var myOptions = {
      zoom: 13,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
 }   

 function showAddress(address,fText) {
  if (map == null) return false;
  if (address == null) return false;
  if (fText == null) fText = "Default Text";
    if (geocoder) {
      geocoder.geocode( { 'address': address}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          var marker = new google.maps.Marker({
              map: map,
              position: results[0].geometry.location
          });
      var infowindow = new google.maps.InfoWindow(
          { content: fText });
     google.maps.event.addListener(marker, 'click', function() {
        infowindow.open(map,marker);
      });
        } else {
          //alert("Geocode was not successful for the following reason: " + status);
        }
      });
    }
 } // end showAddress()

If you are planning to migrate, happy migrating 🙂