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.

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.

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/

Video JS

June 6th, 2010

As I expected, an intermediate period is coming, when everyone will try to make the most of HTML5 but at the same time build good fall-backs. A good example is Video JS, a project that aims to provide the best video playback solution as possible. It’s basically a HTML5 video player with controls built from JavaScript and customizable via CSS, so far nothing we haven’t seen at Youtube, however what makes this good is that it also shows the way to make it fall back to Flow player when the browser does not support Video. In English: this means that this will work even in IE6.

It is very simple to use this library, it can be done in a few steps:

1. Load the library

<!-- Include the VideoJS Stylesheet -->
<link rel="stylesheet" href="video-js.css" type="text/css" media="screen" title="Video JS" charset="utf-8">
<!-- Include the VideoJS Library -->
<script src="video.js" type="text/javascript" charset="utf-8"></script>

2. Initialize when the page is loaded

  <script type="text/javascript" charset="utf-8">
    // Run the script on page load.
 
    // If using jQuery
    // $(function(){
    //   VideoJS.setup();
    // })
 
    // If using Prototype
    // document.observe("dom:loaded", function() {
    //   VideoJS.setup();
    // });
 
    // If not using a JS library
    window.onload = function(){
      VideoJS.setup();
    }
  </script>

3. Insert the video embed code. This may seem complicated at first, to make it easier to understand I put in some extra comments that describe what and when happens.

<!-- Begin VideoJS -->
  <div class="video-js-box">
    <!-- Using the Video for Everybody Embed Code http://camendesign.com/code/video_for_everybody -->
    <!-- Let's try to use that video element if we can -->
    <video id="video" class="video-js" width="640" height="264" poster="http://video-js.zencoder.com/oceans-clip.png" preload>
      <!--Let's try to use MP4 at first-->
      <source src="http://video-js.zencoder.com/oceans-clip.mp4" type="video/mp4">
      <!--If the browser doesn't support MP4, let's try WebM-->
      <source src="http://video-js.zencoder.com/oceans-clip.webm" type="video/webm">
      <!--No MP4, no WebM, well then our last resort is OGG Theora-->
      <source src="http://video-js.zencoder.com/oceans-clip.ogg" type="video/ogg">
      <!--No HTML5 video element support :(, it's probably IE, let's use Flash(Flow player) then-->
      <object width="640" height="264" type="application/x-shockwave-flash"
        data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf">
        <param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" />
        <param name="allowfullscreen" value="true" />
        <param name="flashvars" value='config={"clip":"http://video-js.zencoder.com/oceans-clip.mp4"}' />
        <!--No Flash, let's just show a poster then-->
        <img src="http://video-js.zencoder.com/oceans-clip.png" width="640" height="264" alt="Poster Image" 
          title="No video playback capabilities." />
      </object>
    </video>
    <!--No video element, no Flash, ohh well, offer the user to download the video and use an external player then-->
    <p class="vjs-no-video"><strong>Download Video:</strong>
      <a href="http://video-js.zencoder.com/oceans-clip.mp4">MP4</a>,
      <a href="http://video-js.zencoder.com/oceans-clip.webm">WebM</a>,
      <a href="http://video-js.zencoder.com/oceans-clip.ogg">Ogg</a><br>
      <a href="http://videojs.com">HTML5 Video Player</a> by <a href="http://videojs.com">VideoJS</a>
    </p>
  </div>
  <!-- End VideoJS -->

This library is young, but it is already quite usable. It is the perfect solution for supporting iPhones and iPads.

Homepage: http://videojs.com/

Node.js

May 22nd, 2010

I just watched Ryan Dahl — Introduction to NodeJS on YUI Theater and I am very exited, it surprised me, it sounds really crazy without the details. Today’s web servers mostly use threads or processes for each request they serve. The problem with this is the fact that threads and processes cost resources(CPU cycles and RAM), this is justified by the fact that most requests start and end very quickly, however if we have a lot of concurrent requests things can really heat up. If a web server gets a lot of incoming requests at the same time it needs to have a lot of threads/processes running, which increase the RAM and CPU usage and decrease the response time. This is a grave problem if we have a high traffic site or a chat application which keeps a connection open for a very long time.

So the question may be asked: why do we use threads anyway?

The answer: We could use a nice event loop but the problem is that we have a lot of function calls that block the execution like this one:

result = db.query(“SELECT * FROM foo”);

This line of code will pause our current thread until we get a answer from the database, and it takes long(socket connections etc.). In an event loop we can’t afford to have these instructions pause our loop, that means that we would basically have our clients wait in line.

The resolution: Make them stop blocking us!

So If we were to turn these blocking routines into non-blocking routines we would live in a better world.

Let’s have a look at JavaScript. The browser is one threaded still we are fine with it, we don’t need no threads there: why is that?

It’s because we have instructions like these:

//do something time consuming
$.getJSON('ajax/some.php', function(data) {
  //wake me up when you are done!
  //do something with the result
});

So we have asynchronous, non-blocking routines in JavaScript, that’s why we don’t care about threads.

If this is better, why aren’t people using this instead of threads?

According to Ryan Dahl, this is mostly because of bad habits, it would be somewhat harder to teach non-blocking IO and basically most of the tools we have now have only blocking IO. I feel that the main reason is probably that most languages don’t make writing callbacks easy and simple, unlike JavaScript.

Solution: let’s write a one threaded web server with JavaScript.

This is what Ryan Dahl and others are doing, this is what Node.js is all about. They abstract the ugliness of the underlying libraries and make IO routines non-blocking.

One may note: JavaScript is not the fastest language…

Answer: V8(Chrome’s JavaScript engine) all the way!

Node.js is far from ready for prime time, but it is definably usable in some cases where we would really need it. I recommend those interested in this to watch the video presentation, and to go to http://nodejs.org/, download Node.js(it’s free, MIT license) and give it a try. I successfully compiled it under Debian unstable and now experimenting with it.

How to write a CKEditor image uploader

May 18th, 2010

CKEditor is an awesome piece of software, it’s essential for good CMS-es that require WYSIWYG editing, the problem however that it doesn’t have an image uploader by default and it’s not a trivial task to write one because it’s documentation is not very good at this part. I spent a lot of time googling for hints on how can I write a PHP backend for image uploads, luckily after some hard work I managed to gather enough info to create a working image upload backend.

1. I have an ajax directory relative to the sites root, I will create an upload.php in this folder.

2. I edit the config.js (inside CKEditor’s directory) and append the following line:

//this needs to be inside: CKEDITOR.editorConfig = function( config )
config.filebrowserImageUploadUrl = 'ajax/upload.php?type=Images';

3. This upload.php will have to deal with a HTTP Post Request of course and the file will be sent from an input named “upload”, in PHP this means that we have to deal with $_FILES['upload']. Also we need to respond to CKEditor which is a little tricky, it involves ad-hoc JavaScripting(which was badly documented when I did this the first time). The following template solves the CKEditor specific issues:

<?php
//process $_FILES['upload']
//store uploaded images URL in $uploadedImageURL
?>
<script type="text/javascript">
window.parent.CKEDITOR.tools.callFunction( <?php echo $_GET['CKEditorFuncNum']?>, '<?php echo "$uploadedImageURL"?>' );
</script>

We normally want to resize the image at this point and tell CKEditor the URL of our resized image. This ad-hoc method is mainly for security.

There is also the option for using CKFinder for file uploads, but I prefer doing custom solutions so that I can have maximum control over my file uploads.

Pure CSS3 Spiderman Cartoon w/ jQuery and HTML5 – Look Ma, No Flash!

May 17th, 2010

Last week I came across a very nice demonstration of what the HTML5 stack can do with just CSS(3 to be exact) and some minor JavaScripting.

http://www.optimum7.com/internet-marketing/web-development/pure-css3-spiderman-ipad-cartoon-jquery-html5-no-flash.html

The article describes how the animation was created what problems did it required solving and how could the DOM be used for gaining and advantage.

A commentator replied to this article with a blunt suggestion that “This works in 6% of browsers and spikes CPU usage.” and goes on suggesting that this is not usable because it is not supported everywhere. Well it misses the point because this was a well performed experiment.

The browser vendors will have to give sooner or later, we can’t live with IE6 supported technologies forever.

AJAX and linking

May 4th, 2010

Having a HTML fall-back for an AJAX application is good, but sometimes we still need the benefits of having links. If we want our application to have bookmark-able and/or copy-paste-able states and support the back button we need to put a little extra effort into it.

If the location changes in the address bar, the page reloads, this is unacceptable if we have an AJAX application, but luckily this doesn’t apply to the hash(#) part of the URL. If we change only the hash, the page won’t reload, so generally we can store states inside the hash. To do this it’s possible to use them in HTML with links like <a href=”#foo”> or via JavaScript like “location.hash = ‘foo’;”.

Since it’s easy to store states in the URL, all we need is a way to be notified if the state changes. In HTML5 we have an event for this which is good, in older browsers we don’t have this, which is bad, but luckily there is already a jQuery plugin that takes care of this: It’s Ben Alman’s hashchange plugin.

This plugin is really simple to use for coders already familiar with jQuery, it simply provides an event. Here is an example usage for this:

$(function(){
    // Bind the event.
    $(window).bind( 'hashchange', function(){
        // Alerts every time the hash changes!
        alert( location.hash );
    })
});

This is good, but we still need to get some information out of the hash, for this I made a very simple protocol, the main goal is to be able to call functions and pass parameters:

- the hash is made up by parts

- parts are separated by ‘/’

- the first part is the function we want to call

- the parts after the first one get passed as parameters

For example: #foo/1/2 would call foo(1,2)

To make this safer I create an object where I store the actions I want to be mapped, so here is the code I use:

$(function(){
    //a map of our actions
    var actions = {
        foo:function() {
            alert('foo');
        },
        bar:function(a) {
            alert(a);
        }
    }
 
    //parse the hash and decide what to do
    var actionSwitch = function(){
        var action;
        var h = location.hash;
        h = h.split('#');
        h = h[h.length-1];
        h = h.split('/');
        action = h[0];
        h.splice(0, 1);
        if (actions.hasOwnProperty([action])) {
            actions[action].apply(this, h);
        }
    };
 
    //bind our action switch to the hashchange event
    $(window).bind( 'hashchange' , actionSwitch );
 
    //execude the action switch at start too
    actionSwitch();
});

Of course the actions object should contain real actions. The purpose is to have set of mapped functions that we want to call when the hash changes.

Using a system like this also makes tings a lot clearer and makes our application take advantage of the browsers navigation buttons.