What they don’t teach you in (W3)school: JavaScript variable scoping

January 27th, 2011

W3Fools is an interesting site I came across that highlights the wrong parts of W3Schools. While W3Schools is the most popular online resource for web standards, its content has a lot of serious flaws.

One such problem at W3Schools is variable scoping in JavaScript(w3schools page):

JavaScript has a global scope(global window object to be more precise), that is the place where all global variables go, usage of this must be minimized because in most pages there will probably be scripts from multiple sources, if everyone relies on the global scope, than sooner or later one script will get into conflict with another. The var keyword is not an optional decoration in JavaScript, if we leave out the var, then the global scope is assumed automatically. Here are some examples:

These functions declared global variables, therefore our local variable loses its original value:

something = 'first thing';
 
function foo() {
    something = 'foo';
}
function bar() {
    something = 'bar';
}
 
foo();
bar();
console.log(something); //'bar'

These functions declared local variables, no collisions have occurred here:

var something = 'first thing';
 
function foo() {
    var something = 'foo';
}
function bar() {
    var something = 'bar';
}
 
foo();
bar();
console.log(something); //'first thing'

W3Schools states the following too:

If you redeclare a JavaScript variable, it will not lose its original value.

While it may not cause an error now it is certainly not a good practice and could lead to confusion and maybe runtime errors in future versions of ECMA Script(JavaScript).

There are also other important facts about the var keyword that are not mentioned in W3Schools:

var is function scoped and not block scoped:

function test() {
    if (true) {
         var test = 3;
    }
}

works just like:

function test() {
    var test;
    if (true) {
         test = 3;
    }
}

Either way you will be able to access the variable test after the block. A better example might be:

for (var i=0;i<10;i++) {
}
console.log(i); //10

The best practice to avoid confusion is to begin each function with a single var declaration and declare all variables in that single var declaration. JSLint can help you with that. And learning more about JavaScript is as easy as watching a couple of videos I outlined in one of my previous posts.

Update:
the best comment this article/issue received so far: http://www.reddit.com/r/web_design/comments/fa9hp/what_they_dont_teach_you_in_w3school_javascript/c1ejet7

Update 2: made the w3schools link weaker.

Update 3: added rel=”nofollow” to w3schools links.

Web developer’s guide

December 9th, 2010

I decided to do a compilation of web based resources that help learn web developing. I have strictly sticked to resources that are available on the web for free. I tried to categorize them by skill level. This will probably get revised a lot, I am looking forward to suggestions. Nearly none of this is my own work and I may be biased towards certain authors.

Beginer

Google Code Uniersity is a really good place to start learning the basics of web developing, I recommend the following tutorials:

HTML, CSS, and Javascript from the Ground Up

CSS, HTML and Javascript

AJAX Tutorial

Advanced

YUI Theatre is one of the places that has a lot of interesting talks where a developer can learn more about how the web actually works and how a developer could improve things. These are the ones that I think web developers should watch:

A developer needs to fully understand JavaScript as a programing language.

Douglas Crockford – The JavaScript Programming Language part 1part 2part 3 and part 4 – this is a must view for every web developer, it really helps understand how JavaScript actually works and how we can program in it effectively.

The good parts of the language need to be learned.

Douglas Crockford - JavaScript: The Good Parts

A developer should understand that the browser’s DOM API is broken.

Browser Wars Episode II: Attack of the DOMs – Presented by the Silicon Valley WebBuilder, this event brought together Mike Shaver from Mozilla, Chris Wilson from Microsoft’s IE team, Håkon Lie from Opera, and moderator Douglas Crockford from Yahoo! to talk about the current state of the browser landscape. This video helps understand why is the web broken even today.

Douglas Crockford — An Inconvenient API: The Theory of the DOM

Using libraries is mandatory.

John Resig: “Advancing JavaScript with Libraries” part 1 and part 2 – Johen Resig is the author of jQuery. He talks about how JavaScript libraries work, what they do and how can they help a web developer do more and worrying less about how the DOM works.

Christian Heilmann — YQL and YUI: Building Blocks for Quick Applications

Beyond…

Those who want to create really heavy client side web applications need to aspire for quality.

Douglas Crockford: “Quality” – this can teach a programmer new ways to look at code and measure it’s quality.

Being cutting edge is also very important, if we want to have a future, we must be ready for it.

Brad Neuberg — Introduction to HTML5 – there are a lot of things that are already there and we can make use of.
Brendan Eich — ECMA Harmony and the Future of JavaScript

Speed is very important, it could mean the difference between success and failure, so being able to optimize successfully is a big win.

Joseph Smarr: “High-performance JavaScript: Why Everything You’ve Been is wrong
Nicole Sullivan — Design Fast Websites
Nicholas Zakas – Speed Up Your JavaScript

In terms of CSS a web developer needs to avoid bloating it.

Nicole Sullivan – Top 5 Mistakes of Massive CSS

Starting easy
http://ontwik.com/html5-2/paul-irish-on-html5-boilerplate/

JavaScripting is possible on the server side too, and it can be really powerful.
Ryan Dahl — Introduction to NodeJS
Douglas Crockford — Crockford on JavaScript — Scene 6: Loopage
Dav Glass — Using Node.js and YUI 3

Developers coming from other programing languages

JavaScript is a unique language, and can suprise developers coming from other languages.

C# developers should check out:
How Good C# Habits can Encourage Bad JavaScript Habits: Part 1
How Good C# Habits can Encourage Bad JavaScript Habits: Part 2 – False-y, Testing and Default Values, Comparisons, and Looping

Conditional JavaScript

October 20th, 2010

Having conditional comments and CSS references inside them is good, having conditional comments give the body or html element a class is better, but in my opinion having all this in a JavaScrip file is better.

First thing is to take this code:

var IE = (function() {
  var undef, v = 3, div = document.createElement('div'),
      all = div.getElementsByTagName('i');
  while (
      div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
      all[0]
  );
  return v > 4 ? v : undef;
}());

Now we have a reliable variable called IE which contains either undefined or the IE version. Now we can do real fun stuff with this:

/*IE support*/
if (IE==6) {
    $.getScript('lib/DD_belatedPNG_0.0.8a-min.js', function() {
        DD_belatedPNG.fix('img, .textInput, .apng,.picture-box-frame');
    });
}
 
if (IE) {
    $('html').addClass('ie');
    $('html').addClass('ie'+IE);
}

We can load IE specific hacks from the script tag without bloating the HTML header and we can also add CSS classes to top level elements without filling our HTML header with conditional comments. This is a really clean and flexible approach that doesn’t force you to make your header look like trash.

NoScript

NoScript people will simply tell you that: “If the user has JavaScript disabled this will not work”

According to Yahoo approx. 2% of the US visitors have JavaScript disabled and far less in other parts of the world. But let’s take the 2% for users who for some reason don’t have JavaScript enabled, and discard everyone but the IE users and we get a number that’s far less then 2%. This is highly dependent on the product but if I have to break the experience for less then 2% of my users for the benefit of the remaining 98%, I think I will go with it.

A lot of IE hacks(like PNG hacks) will not work without JavaScript anyway so the user will still have a broken rendering even if I put the conditional CSS in the HTML.

What is NOT a browser

October 4th, 2010

In the beginning computers didn’t have sound capabilities, later on they could get that by inserting optional sound cards. Some computers shipped with sound cards already included, but a lot if not most were shipped without. After a lot of years have passed, most motherboard manufacturers started integrating sound cards into the motherboard. The question here is: what did the multimedia industry do while all of this was happening(for years)?

At first there were apps that emitted sounds by using the PC Speaker, then hybrid apps were born, where the app could use either the PC Speaker or the sound card. Does the industry care about people without sound card today? No. I don’t think it’s even possible to get access to the PC Speaker anymore. I have never seen a game where the game would close caption the sounds if it found out that I didn’t have a sound card, maybe if I am deaf but that’s another story.

The story of  sound card and the PC is very similar to the story of JavaScript and the browser, with the exception that a lot of today’s web developers still insist on making web applications that will work even without JavaScript. JavaScript was invented in 1995(15 years ago) and it’s in every browser that has at least 1% market share, but still we have people who think it’s just optional.

My take is that every web application should work the best it can in every situation but it’s unreasonable to accept it work identically in every situation. If I have a news site it’s reasonable to have the article’s content accessible without JavaScript, but it’s unseasonable to have my lightbox-like gallery work without JavaScript.

Applications that we today call browsers must: understand HTML, render CSS and run JavaScript. There is no in-between if an application can only accomplish one or two of the 3 tasks it’s simply not a browser, it’s something else. We have search engines that typically understand HTML(and a subset of CSS to prevent cheating), in some cases we need to make our content accessible to them, these robots only care about our content, they need to know little about what GUI functions does our site provide.

Knowing all this I only care about two things: search engines and browsers. My first step is always creating HTML to be as semantic as possible(HTML does not make this easy), when that’s done I lay CSS on top of it and make sure it works in modern browsers, then I use a special JavaScript inspired by this post to create elegant IE specific CSS rules. My workflow received criticism because I required legacy(IE) browser to have JavaScript for the CSS rules. I found this dubious because I don’t really think that we can call something a browser if it does not run JavaScript, especially if it’s a legacy application. We should develop for the future not for the past.

We should develop for the majority and not for the minority, if 0.1% of our users have a legacy browser and JavaScript disabled, it’s probably not worth multiplying our development time just for the sake of 0.1% of potential users. The other fact is that if we let users use our web applications without JavaScript they will always feel comfortable disabling it. We need to take the web forward which is impossible if we make our users view JavaScript as an extension.

Any entity with finite resources should consider the above before diving into developing, it’s always important to measure the impact and the resources spent.

Behaviors – Extending HTML

September 13th, 2010

HTML is a markup language which most of the time lacks the elements/capabilities that we really need, not even HTML5 could have all the things we need now and in the future. Most UI frameworks get around this by giving a JavaScript API to create new widgets which utilize the DOM API and CSS to associate looks and behaviors to elements. We don’t need to stop here, we can take this further, we can describe new widgets and extend HTML.

How do we accomplish this?

jQuery has a really powerful method called .live() which can:

Attach a handler to the event for all elements which match the current selector, now or in the future.

So basically we can create CSS like rules for elements with JavaScript. Most of the code we write with jQuery are meant for elements that exist, but with live we can make our code work for future elements as well.

Examples speak for themselves

Let’s say we would want to create a send button which behaves like an input[type=submit] element. Let’s name this tag “send”, and let’s write some markup for it:

<send>Send me</send>

Since this is not a standard HTML element we need to assume that it works like a div and style it:

send {
border: 1px solid #000;
padding: 5px;
cursor: pointer;
}

This styling will only work in older IEs if we hack a little in JavaScript:

document.createElement('send');

Now that we have our new element, but we still need to assign it our desired behavior:

$('send').live('click',function(){
    $(this).closest('form').submit();
});

Translation: whenever you click a send element, submit it’s parent form.

With relatively short and easy to read code, we have created our custom HTML element. Now this is not a very useful element, but that doesn’t mean we couldn’t create something very useful with the same technique. My first idea was to implement the HTML5 placeholder(rollover) feature for browsers that don’t support it.

Sadly jQuery live can only capture events on future elements, but it can’t tell us if a new element has appeared in the DOM, so for this we will need the help of the livequery plugin to give us this feature. Since we are implementing a HTML5 feature we need to be careful and make sure that it’s not already implemented in the browser, for this we will need Modernizr.

The code:

(function(window,document,$,undefined) {
    //check for placeholder support
    if (!Modernizr.input.placeholder) {
        //default to placeholder when loose focus
        var blur = function(e) {
             if (!$(this).val().length) {
                  $(this).val($(this).attr('placeholder'));
             }
        }
        //if the value is the placeholder, empty the field
        var focus = function(e) {
             if ($(this).val() == $(this).attr('placeholder')) {
                  $(this).val('');
             }
        }
        //assign the events
        $("input[placeholder]").live('blur',blur);
        $("input[placeholder]").live('focus',focus);
        $("input[placeholder]").livequery(blur);
    }
}(window,document,jQuery));

Download Examples

Again with relatively little pain we managed to make a HTML5 feature work in all browsers. Of course we could have written a jQuery plugin extension for this, but it’s a lot cleaner to simply think HTML5 and let the browser use it’s built in feature if it has any. jQuery live can be used for a lot of other purposes, in my opinion it is definitely worth learning and using along with the livequery plugin.

The road to HTML5 – Tags

August 12th, 2010

It is probably clear in everyone’s mind that we need HTML5 we can’t go forward without something new, we can’t live off the same decade old technology forever, but still we want to support the old versions of IE, some people can’t even let go of IE 6.

When I started thinking about this, the first question that came into my mind is: why? why do we need various HTML5 technologies?

The first thing that came into my mind were: tags

We need more tags, for applications that care about the semantic structure of our pages, like search engines. We could make search engines identify our content much easier if we can tell them more precisely what semantic meaning does a tag have.

Today’s(and even yesterday’s) browsers were designed to deal with unknown tags, if a browser doesn’t know a tag, it will simply display it’s content, which is almost good, but we need to style it. Luckily it turns out that there is a hack to make even IE 6 apply stylings to undefined tags. I took a look if there are reliable implementations of this.

Here are the implementations I found:

HTML5 Reset (html5reset.org)

This project claims to be a good starting point for developers who want HTML5 tags, fair enough. I loaded it’s homepage in IE 6 and it blew up with a JavaScript error, a “null or not an object” type error that could have been easily caught. I wanted to download this to examine it further, there were 3 download options:

Since I only want a starting point I started off with the Bare Bones version. To my surprise it didn’t have any JS files, so I wondered how they managed to tackle the styling issue that I wrote about above. To my dismay styling didn’t work in IE 6, because it missed the JS hacks required for styling to work.

Since the Bare Bones version didn’t work out I went on and tried the Kitchen Sink version, to my surprise it immediately recommended HTML5 Shiv for IE compatibility in comments, but it used Modernizr which basically provided the same solution.

Since this template had a lot of files, I looked at it’s file structure:

.
|-- [       4096]  -
|   |-- [       4096]  css
|   |   |-- [        133]  core.css
|   |   |-- [        404]  main.css
|   |   |-- [       4096]  _patches
|   |   |   |-- [        132]  mac-ie5.css
|   |   |   |-- [          0]  win-ie5.css
|   |   |   |-- [          0]  win-ie6-below.css
|   |   |   |-- [          0]  win-ie7.css
|   |   |   |-- [        117]  win-ie-all.css
|   |   |   `-- [        218]  win-ie-old.css
|   |   |-- [       4096]  _print
|   |   |   |-- [          0]  core.css
|   |   |   `-- [        128]  main.css
|   |   `-- [       1670]  reset.css
|   |-- [       4096]  img
|   `-- [       4096]  js
|-- [        807]  index.html
`-- [       1488]  license.txt

6 directories, 13 files

(Bare Bones version)

I found out that it has:

  • 2 empty directories
  • 4 empty CSS files
  • supposed support for IE 5 and IE 5 on the mac
  • awkward directory names, using “-” as a directory name
  • html5reset-barebones/-/css/core.css contains only one rule
  • html5reset-barebones/-/css/main.css contains only 3 imports nothing else
  • html5reset-barebones/-/css/_print/main.css contains an import to an empty CSS file
  • the only useful part of this whole package is html5reset-barebones/-/css/reset.css which is basically “html5doctor.com Reset Stylesheet”

In my opinion the Bare Bones package is useless, all it does is include html5doctor.com Reset Stylesheet, which I could probably do myself without having this awkward directory structure.

The Kitchen Sink version is basically the Bare Bones version, plus 2 JS files and a more complex index.html, it includes Modernizr and a JS file that captures the load event with jQuery twice and does nothing, this was probably meant to be template, but then why do the same thing twice?

Bottom line: treat HTML5 Reset only as a sample that showcases some techniques instead of a real starting point, it’s mainly Modernizr with some sample code.

HTML5 Boilerplate

This template promised a lot of IE compatibility. This template uses html5doctor.com Reset Stylesheet too, along with other CSS frameworks like YUI Reset. This template has some good patterns and examples like how to handle mobile orientation changes correctly but I wouldn’t use this as my starting point, it includes too many things like DD Belated PNG for IE6, which someone may or may not need. It basically uses Modernizr to get the job done, to be fair the author of HTML5 Boilerplate is a contributor to Modernizr.

Bottom line: it has good examples on how to accomplish various tasks but it’s too bloated to be a general template and it lacks documentation and modularity.

Modernizr(http://www.modernizr.com/)

Modernizr is a very helpful tool, both HTML5 Reset and HTML5 Boilerplate use it as a starting point. It basically detects the presence a lot of HTML5 features mostly by using tests, which is very good, it doesn’t try to provide fallbacks for missing features, the only thing it fixes is the tag styling for older IEs.

HTML5 Shiv(http://code.google.com/p/html5shiv/)

If someone only wants to fix the tag stylings in IE and does not need the full feature set of Modernizr, then HTML5 Shiv is a good tool for that.

HTML5 Reset Stylesheet(http://html5doctor.com/html-5-reset-stylesheet/)

This stylesheet is pretty good, if I would combine it with YUI Reset and get the ultimate Reset stylesheet. The only problems I have with this is that it defines default styles in a few places, which I don’t really like, because I will probably override them anyway.

Conclusions:

I personally would use either HTML5 Shiv or Modernizr with HTML5 Reset Stylesheet(both templates encourage that) with my other technique. HTML5 Reset is an overkill because it has too many conditional CSS files, no site requires that many. HTML5 Boilerplate encourages a better practice for conditional CSS by giving the body tag a class that corresponds with the IE version.

If I were to choose from the two templates I would probably go with HTML5 Boilerplate, but I would surely remove what I don’t need :)

There is nothing there to stop web developers from start using HTML5 tags right away for providing a more semantic web!

jQuery AJAX Enhance

July 7th, 2010

It is probably clear as the sky that I have much love for jQuery, it’s a tool that saved me time and money. The good thing about jQuery is that it is simple, and it allows extensions(plugins), which make it virtually invincible.

I was working on a project where I had a lot of jQuery UI Dialogs, with forms and OK and Cancel buttons. I virtually repeated the same code over and over: if the user clicks Ok, submit the form, which is easier said than done. $.ajax is awesome, and I could easily send form data if I combined it with $.serialize, so it wasn’t that bad, but then I thought to myself, what if I’d make a version of $.ajax that was for forms.

So my idea was to have:

$(formselector).ajaxPost(url,func,dataType);
$(formselector).ajaxGet(url,func,dataType);

and make these work just like $.ajax, it would serialize the form data and send it. Naturally if I would leave out the url parameter it would try to detect it from the action attribute of the form.

This was very good, it worked, but still it wasn’t enough, I couldn’t do file uploads with these, because to my best knowledge, jQuery doesn’t support it. I could not accept not having file uploads so I took YUI Connection Manager(which supports file uploads) and wrapped it around my jQuery-ish syntax.

The result is the following:

$(formselector).ajaxUpload(url,func,dataType);

Which almost works like my previous extensions with the addition, that it can upload files. This feature is dependent on YUI Connection Manager(bundled in package), if it’s absent, the usage of this method will throw an exception, however the other two will work as expected, because they are fully coded in jQuery. This of course means that if there is no need for file upload support, the YUI components can simply be left out.

If anybody would be interested in this, it’s available under MIT and GPL, go grab it and hack it:

Download jQuery AJAX Enhance 0.9

Raphaël – Cross browser drawing API

June 22nd, 2010

I already talked about Excanvas, it is good library that mokey patches  IE to support the HTML5 canvas, just recently I discovered Raphaël, which takes another approach for drawing stuff on the web. Raphaël is a canvas-like framework that has it’s own API for drawing, it uses VML on IE, just like Excanvas, but on better browsers it uses SVG. Overall Raphaël is not a duplication of Excanvas, Excanvas is a cross-browser implementation of Canvas, while Raphaël is a cross-browser implementation of SVG.

Raphaël’s demos so far are a lot more impressive than the ones that come with Excanvas, but it’s biggest advantage is that it has an API documentation unlike Excanvas which refers to the not so good W3C documentation. The reason it is bad to point to a W3C documentation is because Excanvas doesn’t implement all of those, so we have to test and see what is implemented and what is not.

The classic tiger example done with Raphaël

The Raphaël API is simple, it focuses on the things people would normally do:

window.onload = function () {
    var img = document.getElementById("photo");
    img.style.display = "none";
    var r = Raphael("holder", 600, 540);
 
    r.image(img.src, 140, 140, 320, 240);
    r.image(img.src, 140, 380, 320, 240).scale(1, -1).attr({opacity: .5});
    r.rect(0, 380, 600, 160).attr({gradient: "90-#000-#000", opacity: .5});
};

Flash advocates criticized native web applications because it was not possible to do reflections and the reflections had to be stored server side. The above example, proves them wrong, it does exactly that without the need of storing the image server side.

A great feature of Raphaël is that the drawn elements are actually DOM elements, which makes their events scriptable. This means that we can do interactive objects just like this example.

The Raphaël project goes even further, it even has a charting plugin, which can make it really convenient to do interactive graphs. This makes me wonder why does Google Analytics still use Flash.

Thanks to developers like these we don’t have to wait 10 years for the pure HTML5 Canvas and SVG. I may have given a lot of credit to this project, but there are usecases when Excanvas is probably better, the key for choosing is considering the functionalities and speed.

Avoiding the frustration of web designing as much as possible

June 19th, 2010

Every web designer and developer knows that the web is full of mess and it can be very challenging to create beautiful designs and advanced user interfaces. We all have been there, we all have done that. Web browsers follow their own path, CSS is terrible and counter intuitive for layouts. I wrote this article for both web designers and web developers, I did my best to avoid getting into deep coding.

So the question is: is there a way out of this madness? is there a way we can stop worrying more about compatibility than about our actual product?

It turns out there is a way, there is a way to get rid of most of the annoyances, so here are my tips for you to stay alive:

  1. Browser defaults are evil. Neutralize them! The YUI(Yahoo User Interface) Reset and YUI Fonts library can help you out here, you just include two CSS-es, and you can say bye bye to browser defaults. This eliminates the need to constantly monitor your design in multiply browser to check for conflicting defaults.
  2. CSS is counter intuitive for layouts, and is affected by a lot of browser quirks. You need to use a CSS library for layouts so you don’t have to worry about this. YUI Grids can help you out with this, it can really make building the skeleton of your website painless, also it is very much mobile compatible, which saves you work on mobile devices.
  3. Use a doctype that brings the best behavior out of most browsers, you don’t want your page to render in quirks mode.

This may seem to be easier said then done, but it’s actually easy to do too. There is a secret cheat code for the easier way out, type “yui grids builder” in Google search, and click “I’m feeling lucky”. I you perform this action correctly you are presented with this tool, which enables you to simply create a skeleton for your site and click “Show code” when you are done. You get a very good starting point for free, you get a layout, that is cross-browser. It is much easier to create a design based if you have this starting point.

Mobile web libraries – Sencha Touch

June 19th, 2010

When I thought I was through examining the most appealing mobile web libraries, the news came in that the newly (re)formed Sencha has put out a new one called Sencha Touch. Despite being something really new, it provides the best support for iOS(iPhone,iPod,iPad) and Android, in fact it only supports these:

Our initial beta is compatible with iOS and Android, which together represent over 90% of current US mobile traffic.

I neither agree nor disagree with this statement, though I agree that most mobile web market share does in fact come from iOS + Android. Typically this framework is aimed at developers who want to support these, and developers who want to support new technology. Sencha Touch heavily utilizes Webkit, CSS3 and HTML5, it doesn’t seem to be forgiving lesser user agents, this is what seems to differentiate it from jQTouch, despite the fact that Sencha claims to be: Ext JS + jQTouch + Raphaël. They however mentioned that they plan to support other forward thinking devices.

Sencha Touch seems to be the only mobile web framework so far that provides touch support like: tap, double tap, swipe, tap and hold, pinch, and rotate. The problem I found with this is that there is no compatibility chart for Sencha Touch and few of it’s examples actually work on my Android 1.6 phone, which questions Sencha Touch’s Android support.

A weird fact is that Sencha Touch’s API is really Ext JS(see source), even the source codes use the Ext global object. The release I downloaded is labelled 0.90 beta, which discourages me to use it for actual products, because it will probably get a refactoring by the time it reaches 1.0, in fact I wouldn’t have called this beta in the first place.

My final verdict is to use this framework only if it makes sense, it is a superior alternative to writing native applications(because we don’t have to do platform specific builds), but it’s not as compatible as one would expect, which can be a problem because of the Android platform fragmentation. What I would like to see in the future is some jQuery integration(because of jQTouch) and a more forgiving interface, possibly a way to know the browser’s features, my biggest need is a good way to detect drag n drop support.

Update 2010-06-24:

A lot of HTC(and probably others) Android phones will get an upgrade to Android 2.1, which will (hopefully) render some of my above arguments irrelevant. Also worth noting that Sencha Touch is about being future-ready, which in the current circumstances is more reasonable than the opposite.

http://androidcommunity.com/htc-tattoo-getting-2-1-20100311/

http://phandroid.com/2010/03/11/htc-tattoo-getting-android-2-1/