Archive for the 'JavaScript' Category

My online footprint lately

Wednesday, July 23rd, 2008

This is a sort of a catch-up post for listing what I've been up to lately.

  • YUI Blog just published my first article, I'm so proud. It's about loading JavaScript in non-blocking fashion, because JavaScripts, they, you know, like, block downloads. Luckily, there's an easy fix - DOM includes, which I've previously discussed, discussed and discussed.
  • SitePoint published an update to my older article that introduces AJAX, ok, Ajax, by creating a command-line-like interface with PHP on the server side. The updated article features improved code, jQuery example, YUI example, JSON discussion and example. Check it out, bookmark and recommend to your friends that keep asking you "What's this AJAX (they are new, don't know it's now spelled "Ajax") thing? Do you know of a good article?"
  • YDN (developer.yahoo.com) published a video presentation of me and my lovely teammate Nicole Sullivan where we talk about some new and cool front-end performance techniques. So if you wandered how I look and are eager to hear my fabulous Balkan peninsula accent, give it a shot. The talk is called "After YSlow 'A'" and is targeted at those of you who have reached performance nirvana, but are still hungry for more. We talk about preloading components, post-loading, javascript, images, using flush() in PHP to send first byte early on and other fun stuff.
  • Last, not least, I decided to try and find some time to update my JavaScript patterns site. Unfortunately I got sidetracked (yep, I'm easily distracted by shiny objects) and played with a not-so-javascript pattern. The post I published (includes a pretty lame screencast! and) demonstrates how you can use animated background position to indicate loading progress.

Whew, c'est tout pout ce moment, expect a lot more now that the JavaScript book is out of the way. Ah, yep, if you feel like it, join me on Facebook, I created a JS book page.

 

The JavaScript book is almost there

Wednesday, July 16th, 2008

Whew, after a whole year of writing, preparation, edits, blood, sweat, tears, I finished all the latest edits and reviews for my new book, Beginning Object-Oriented JavaScript. It should be out any day now. I can't be happier!

cover.png

You can pre-order with 10% off from the publisher's site.

 

Load a photo in a canvas, then flip

Saturday, May 3rd, 2008

zlati-nathalie.jpg

Today our family went to the yearly photo session with the girls. We took one shot that can be looked normally, as well as upside down, so I was wondering can you flip an image using a canvas tag. Turns out, yes, you can and it's pretty easy.

» Demo is here.

How to load an image in a canvas tag?

Start unpretentiously with an empty canvas tag:

<canvas id="canvas"></canvas>

Now the javascript. Two variables to store a handle to the canvas element and the 2D context of the canvas:

var can = document.getElementById('canvas');
var ctx = can.getContext('2d');

Now let's load an image into the canvas. Using the new Image() constructor you can create an image object, then set its src property to point to the location of the image file. Then set an onload handler for the image which is an anonymous function to be called when the image is done loading. There you put the image inside the canvas using the drawImage() method of the canvas context.

var img = new Image();
img.onload = function(){
    can.width = img.width;
    can.height = img.height;
    ctx.drawImage(img, 0, 0, img.width, img.height);
}
img.src = 'zlati-nathalie.jpg';

You can also notice how the dimensions of the canvas are adjusted to match the dimensions of the image.

How to flip the image upside down

The canvas context provides a rotate() method. The rotation always happens around the top left corner of the image, so we first translate() the image to the bottom right. This way when the image is rotated, it fits back into the canvas. (There is also a one pixel correction, I have no idea why, just saw that the image wasn't flipping exactly otherwise). Assigning this functionality to the onclick:

can.onclick = function() {
    ctx.translate(img.width-1, img.height-1);
    ctx.rotate(Math.PI);
    ctx.drawImage(img, 0, 0, img.width, img.height);
};

C'est tout! Once again, the demo is here.

 

strftime() in JavaScript

Friday, April 25th, 2008

Philip "Bluesmoon" Tellis has posted a tiny (under 3K minified) JavaScript library to format dates, inspired by PHP's strftime()

Examples:

d.strftime('%Y/%m/%d')
» en: 2008/04/25
» fr: 2008/04/25
» de: 2008/04/25

d.strftime('%A, %d %B')
» en: Friday, 25 April
» fr: Vendredi, 25 Avril
» de: Freitag, 25 April

There's also a demo to fiddle with.

I've previously had fun with kinda like the opposite: translating human-readable times into JS Date objects. Also here and here you have strtotime() look-alikes that take human-readable dates and turn them into Date objects.

 

When client-only validation is good for business

Sunday, April 13th, 2008
You should never never ever rely on client-side validation only. Client-side validation is for enhancing user experience, server-side is the validation. This is a rule, never to be broken. But here's a funny story how skipping the server-side validation actually helped.

This is a real story, but the actual names have been replaced in XXX, just not to make other people look bad :D

There is this site called xxxxxxxxx.com that charges you $XX membership access. Having just moved from Canada, last year I didn't have a US credit card to pay the fee and tried to use my Canadian visa. Problem: the input field for postal code (zip code) accepts 5 characters only, since the zip codes in US a like 90404, 90066 and so on. A Canadian postal code is like H0H-0H0 or H0H0H0, six characters. So seemed like I couldn't pay online. Or could I?

Checking the source code with Firebug gives me this:

client.png

From here it's trivial to change maxlength attribute of the input. Even with IE it's super easy just to type in the address bar something like:
javascript:document.getElementsByName('XXXXXXX')[0].maxLength = 100;

So I did change it, typed my Canadian CC#, Canadian postal code and submitted the form, crossing fingers that the developers who built the site were too pressed by deadlines to do a proper server-side validation. Lo and behold, it worked!

At the end with the help of an innocent client-side tweak I got what I needed (membership), xxxxxxxx.com got more business, and everybody's happy.

There's a lesson in this: sometimes being too strict in data validation for things that don't matter is just in your way.
And another: don't assume all your potential clients are from US.

 

JSPatterns.com up again

Wednesday, March 26th, 2008

After getting 300 megs of wiki content spam, I deleted the old wiki over at http://www.jspatterns.com.

Now restarted the project as a blog with static pages for the javascript patterns and blog posts for anything interesting in the ever so exciting world of JavaScript. So far nothing special there (example), but keep an eye on it, as I plan to fill up the TOC (recovered from the old wiki) with top quality content ;)

I suck at design and wasted two nights to come up with some custom wordpress theme for the new blog. I like the result, but that's just me. I also made the theme available for download, in case someone wants to consider it for a future project.

Talking of spam, yesterday my host deleted 2 gigs!!! of email spam from my hosting account, how crazy is that.

The new JSPatterns.com is running the latest release candidate WordPress 2.5, slick stuff.

 

JoJo: Javascript Junk generator

Tuesday, March 25th, 2008

Ever needed to be able to generate random, but valid JavaScript code? Well, today is your lucky day: meet J.J. or JoJo, the Javascript Junk code generator.

All you need to specify is how many kilobytes of code you need. Available also as a web service.

» tools.w3clubs.com/jojo

If anyone can think of any application of JoJo, other than performance experiments, I'll be most intrigued to hear it.

 

sleep() in JavaScript

Monday, March 24th, 2008

PHP has a sleep() function, but JavaScript doesn't. Well, this is because it's useless, you might say, and you'll be right. But for simulating heavy processing and for misc performance measurements, it could be useful. So here's how you can go about creating a sleep() in JavaScript.

The code

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

Usage

Sleep for 1 second (1000 milliseconds):

console.log(new Date());
console.log('Dude!');
sleep(1000);
console.log(new Date());

Result in Firebug's console:

sleep.png

 

PHP-style $GLOBALS in Javascript?

Saturday, March 8th, 2008

Javascript has implied globals. When you skip the var in var a = 1; and go a = 1;, then a becomes a global variable. Some consider this an error in the language. Global variables should be avoided because they tend to overwrite each other in unexpected places, especially if the project grows in LOC and number of developers.

In PHP on the other hand, variables are local. If you need a global variable, then you have to have to be explicit about it using the $GLOBALS superglobal array.

So how about this: adopt the $GLOBALS convention in your JavaScripts? At the top of the script you go:

$GLOBALS = {};

Then every time you need a global variable, you do:

$GLOBALS['myglob'] = 1; // very PHP-like

or if you prefer:

$GLOBALS.myglob = 1;

Benefits of the approach:

  • global variables easy to spot (even from an aeroplane)
  • if it's not $GLOBAL, it's meant to be local. If it's missing the var, it's an error

Drawback:

  • It's a convention, so it can only help, but not enforce any coding practices

How many globals

Here's a quick test to check how many globals you have in a page.

(function(){
  var globs = 0;
  for (var i in window){
    globs++;
  }
  alert(globs);
})()

Run this script in your page without the scripts. Then add the scripts to the page run again. The result should be only one more global var if you followed the $GLOBALS convention.

 

Canvas pie with tooltips

Saturday, March 8th, 2008

This is very flattering: Greg Houston took my script for DIY canvas pie and added tooltips and better colors logic. Here's the result, it's really nice, built with some MooTools. The tooltips are not supported in <canvas> but Creg used an image that overlays the pie and set the tooltips with an image map. Clever, isn't it?

I just used random colors for the pieces of the pie, but Greg knows better. Based on a tutorial by Jim Bumgardner, he was able to achieve much more pleasing, yet reliable results. Funny thing that Jim works in Yahoo! two floors above me (used to be even on the same floor).

Check the demo and the post, cool stuff, works in IE too!

 

replace selected text (Firefox)

Thursday, March 6th, 2008

A quick function to replace the selected text (in Firefox). Accepts:

  • string to replace the selection, or
  • callback function that takes the selected text and returns a string to replace the selection
function replaceSelection(t) {
  if (typeof t === 'function') {
    t = t(window.getSelection().toString());
  }
  var range = window.getSelection().getRangeAt(0);
  range.deleteContents();
  range.insertNode(document.createTextNode(t));
}

Usage:

1. Replace selected text with "dude"
replaceSelection('dude');
2. Uppercase the selected text
replaceSelection(function(s){return s.toUpperCase()});
3. Lowercase the selected text
replaceSelection(function(s){return s.toLowerCase()});

Luckily I'm so close (and yet so far) to finishing this book, otherwise I won't be able to help myself but create a whole toolbar of bookmarklets for "power" Google doc users

 

Canvas pie

Tuesday, February 5th, 2008

OK, so you have an HTML table. Let's turn it into a pie chart with a bit of javascript.

We'll be using the canvas tag, so the browser has to support it. For IE - well, you still have the table. That's why we'll call it progressive enhancement. Unobtrusive too. Here's a screenshot:
canvas-pie.png

» The demo is here (refresh for new colors)

Here are the ingredients to the recipe:

  1. One <canvas> tag
  2. One <table> full of data
  3. javascript to get the data from the table
  4. javascript to plot the data on the canvas

One canvas tag

<canvas id="canvas" width="300" height="300"></canvas>

One table full of data

This is a bare bone unstyled old school table.

<table id="mydata">
    <tr>       <th>Lang</th><th>Value</th> </tr>
    <tr><td>JavaScript</td>  <td>100</td>  </tr>
    <tr><td>       CSS</td>  <td>200</td>  </tr>
    <tr><td>      HTML</td>  <td>300</td>  </tr>
    <tr><td>       PHP</td>  <td> 50</td>  </tr>
    <tr><td>     MySQL</td>  <td> 30</td>  </tr>
    <tr><td>    Apache</td>  <td> 10</td>  </tr>
    <tr><td>     Linux</td>  <td> 30</td>  </tr>
</table>

javascript to get the data from the table

First, some setup. Let's tell the script which is the ID of the data table, the ID of the canvas tag and which column contains the data:

// source data table and canvas tag
var data_table = document.getElementById('mydata');
var canvas = document.getElementById('canvas');
var td_index = 1; // which TD contains the data

Next, select all table rows, then loop through the rows, selecting all TDs. Add the data we need to a data array. While at it, run a total of the data in the column and also create an array of random colors. Paint each row with the selected color. (we'll see the actual getColor() in a bit.)

var tds, data = [], color, colors = [], value = 0, total = 0;
var trs = data_table.getElementsByTagName('tr'); // all TRs
for (var i = 0; i < trs.length; i++) {
    tds = trs[i].getElementsByTagName('td'); // all TDs

    if (tds.length === 0) continue; //  no TDs here, move on

    // get the value, update total
    value  = parseFloat(tds[td_index].innerHTML);
    data[data.length] = value;
    total += value;

    // random color
    color = getColor();
    colors[colors.length] = color; // save for later
    trs[i].style.backgroundColor = color; // color this TR
}

javascript to plot the data on the canvas

Time for the fun part, the drawing! First, we need to create a context object. Then figure out the raduis of the pie and the center, all based on the width/height pf the canvas tag:

// get canvas context, determine radius and center
var ctx = canvas.getContext('2d');
var canvas_size = [canvas.width, canvas.height];
var radius = Math.min(canvas_size[0], canvas_size[1]) / 2;
var center = [canvas_size[0]/2, canvas_size[1]/2];

Next, let's loop through data and paint pieces of the pie. To draw a piece of pie, you basically need to call these methods of the context object:

  • beginPath() - to start the piece of the pie
  • moveTo() - to set the pencil in the center
  • arc() - draw a piece of a circle
  • lineTo() - finish the circle piece with a line back to the center
  • closePath() and fill() but set the fill color first.

Here's the actual code for this part, hopefully the comments help:

var sofar = 0; // keep track of progress
// loop the data[]
for (var piece in data) {

    var thisvalue = data[piece] / total;

    ctx.beginPath();
    ctx.moveTo(center[0], center[1]); // center of the pie
    ctx.arc(  // draw next arc
        center[0],
        center[1],
        radius,
        Math.PI * (- 0.5 + 2 * sofar), // -0.5 sets set the start to be top
        Math.PI * (- 0.5 + 2 * (sofar + thisvalue)),
        false
    );

    ctx.lineTo(center[0], center[1]); // line back to the center
    ctx.closePath();
    ctx.fillStyle = colors[piece];    // color
    ctx.fill();

    sofar += thisvalue; // increment progress tracker
}

utility

Here's the function that gives a random color:

    // utility - generates random color
    function getColor() {
        var rgb = [];
        for (var i = 0; i < 3; i++) {
            rgb[i] = Math.round(100 * Math.random() + 155) ; // [155-255] = lighter colors
        }
        return 'rgb(' + rgb.join(',') + ')';
    }

C'est tout! Enjoy your pie :D

UPDATE: Comment by Zoltan below, if you use Explorer Canvas, you can make this work in IE with only this:
<!--[if IE]><script type="text/javascript"
src="/path/to/excanvas.js"></script><![endif]-->

 

MP3 player from Yahoo! - bookmarklet

Wednesday, January 23rd, 2008

Update Jan 30, 2008: updated code based on comments and code from Carl

Here's the scenario: you have a page that links to some .mp3 files. You add a line of code in your page and lo and behold, there's a nice media player embedded into the page. Your visitors no longer have to download the MP3s, they can just stream it right there. All the mp3s on the page become part of a playlist.

The line in question you need to add to your page is:

<script src = "http://mediaplayer.yahoo.com/js"></script>

More about the player here - yahoomediaplayer.wikia.com

For examples of sites using this player in the wild, try aurgasm.us

A bookmarklet

Now, here's what you can do if you want to use the player, but the web site owner haven't incorporated it yet. Take the player with you. Run my bookmarklet that will simply insert the required javascript into the page.

So here goes in two easy steps:

  1. Grab the bookmarklet:

    Right-click, add to favorites

  2. Go to any page that links to MP3s and click your new shiny bookmarklet

    Enjoy!

Source

The readable source code of the bookmarklet:

javascript:(function(){

  var start = function(){YAHOO.music.WebPlayer.asyncLoadPlayer()};

  var script = document.createElement('script');
  script.src = 'http://mediaplayer.yahoo.com/js';

  if(script.addEventListener){
    script.addEventListener("load", start, false);
  } else{
    script.onreadystatechange = function(){
      if(this.readyState=="complete"){
        start();
        script = null;
      }
    }
  }
  script.type="text/javascript";
  document.getElementsByTagName('head')[0].appendChild(script);

})();
 

YUI pie chart example

Wednesday, January 16th, 2008

If case you haven't noticed - YUI Charts hit the streets.

As with everything new, it's best shown and understood by example. So here's the simplest example of using a pie chart. Basically I took the example from the YUI page, changed all the paths to point to yahooapis.com (where YUI is hosted for free) and stripped everything that could be stripped (there's even no html or head tags, but turned out the body tag is required). The result is a short html with all dependencies satisfied.

OK, so here's the example, grab, paste, customize:
chart.html

 

Table to chart via JavaScript

Tuesday, January 8th, 2008

A javascript by Christian Heilmann that takes a table from your page and constructs the URL to request a chart from Google APIs. Slick and accessible. Check it out.

 

Netflix - how many movies you've rented

Sunday, December 30th, 2007

Netflix is a great service, it's a shame they don't seem to provide any APIs. Oh, well, we'll have to resort to other means of extracting data.

A little javascript to count how many movies you've rented:

document
    .getElementById('returned_movies')
    .getElementsByTagName('tbody')[0]
    .getElementsByTagName('tr')
    .length

You can put this code in a bookmarklet or simply type in the Firebug console.

As people say "your markup is your API".

 

Fancy formatting

Friday, December 21st, 2007

Writing readable code means proper indentation. Usually you'd tab (or use 2 or 4 or 3 spaces) after every curly bracket. Something like this:

if (true) {
    // indent
    if (false) {
        // another indent
        // and some more
    }
}

Same goes when you have a bigger hash/object sort of thing:

var memememe = {
    name: 'Stoyan',
    family_name: 'Stefanov',
    blog: 'http://www.phpied.com',
    kids_count: 2,
    books_count: 3,
    occupation: 'programmer'
}

Sometimes I find myself going a little fancy and aligning all the values in the name/value pairs:

var memememe = {
    name:        'Stoyan',
    family_name: 'Stefanov',
    blog:        'http://www.phpied.com',
    kids_count:  2,
    books_count: 3,
    occupation:  'programmer'
}

But recently, inspired by Firebug's Net panel way of presenting header information, I tried aligning the keys to the right in addition to aligning the values to the left. So I ended up with something like this:

var memememe = {
          name: 'Stoyan',
   family_name: 'Stefanov',
          blog: 'http://www.phpied.com',
    kids_count: 2,
   books_count: 3,
    occupation: 'programmer'
}

Fancy, eh? I liked the way it looks. But then I thought that when writing maintainable code, anything fancy suggests uncommon, uncommon suggests that other team members won't be using it, so it means breaking the rule #1 of writing maintainable code: be predictable. (this also happens to be rule #1 of other common activities, such as driving on the highway and designing usable web sites)

This type of formatting is also not easy to type in an editor, so it will require a little more effort. Those two drawbacks are enough, I believe, to dismiss this idea. But I can't help myself liking the way the code looks. Here's a piece of PHP, which looks even better than javascript, because even more characters are centered.

<?php
$memememe = array(
          'name' => 'Stoyan',
   'family_name' => 'Stefanov',
          'blog' => 'http://www.phpied.com',
    'kids_count' => 2,
   'books_count' => 3,
    'occupation' => 'programmer'
);
?>

Ain't that cool?

 

The Front-end Cerberus

Thursday, October 25th, 2007

Some smart guys picture the distinction of content (HTML), presentation (CSS) and behaviour (JavaScript) as a three-legged stool. This is totally fine, but can't we draw a more heroic picture of today's Front-end developer?

frontend-cerberus.jpg

I found the image here, if anyone knows the original author, let me know so I can give proper credit.

BTW, I never knew what Cerberus meant until 15 minutes ago. The thing is that where I come from, we used this name to refer to some of the teachers that weren't very nice to us at school :)

 

My performance article up on SitePoint

Thursday, October 25th, 2007

click

 

JS/PHP string concatenation mistype

Thursday, October 25th, 2007

Another one from the "this is not a syntax error" department.

The front-end developer is a strange beast who has to jiggle to and fro and code in several languages literally at the same time - javascript, html, css, php or some other server side language, some SQL dialect… No wonder that sometimes we make silly mistakes like:

var $myarray;
var array = array();
$myarray = [];
foreach(var i in myarray)

Last night I just did a silly mistake like this. In JavaScript I used the PHP way of concatenating strings. Something like:

var user = 'Stoyan';
alert('hello ' . user);

This is obviously wrong, but the thing is that it's not a syntax error as one might expect. It alerts "undefined". Why is that?

Well, 'hello' is a string object. You can call methods and properties on it, like:

>>> 'hello'.toUpperCase()
"HELLO"
>>> 'hello'.length
5

And spaces don't matter…

>>> 'hello'     .   length
5
>>> 'hello'  . toUpperCase()
"HELLO"

So 'hello' . user is an attempt to access the "user" property of the string object 'hello'. This property doesn't exist, hence the "undefined" result.

Doing the opposite (using JavaScript-type concatenation in PHP) is also not an error:

$user = 'Stoyan';
echo 'Hello ' + $user; // prints 0
 

"Save AnyThing" offline with a Google Gears bookmarklet

Friday, October 19th, 2007

Here's a little bookmarklet I came up with, I called "SAT", stands for "Save AnyThing (for offline reading)". It uses Google Gears and works like this:

  • you're about to go offline (maybe boarding a plane) and want to catch up on some reading
  • you visit any page
  • you click the SAT bookmaklet
  • it saves all the pages that are linked from the current page (only those on the same domain, you know, security and stuff)
  • you disconnect from the Net and read offline

Pretty cool, eh?

Initially I wanted to experiment with Google Gears and write a phpBB extension to save the latest forum topics for offline reading. But after thinking about it a bit I thought it can be done in an even more generic way and save anything for offline reading. All you need is a page that has a bunch of links, any page - a forum, a blog, the array section of the PHP manual… anything. After you run the bookmaklet, you'll have an offline copy of all the linked pages. Gotta love those bookmarklets, nothing to install, just a click in the favourites.

Demo

satdemo.png

» Click here for a recorded demo

(demo is kinda clumsy, my first attempt in screen recording, I used Adobe Captivate, pretty bad I couldn't upload the result to youtube)

For a live demo, you can also test the bookmarklet by simply clicking the download links below.

Download

Drag those two links to your favorites/bookmarklets. The first one is to store offline pages, the second is to remove the stored versions.

Source code

If you want to take a peek at the source code, the human-friendly versions are here:

Note on pages that will not be stored offline

Not all pages will be stored offline. I'm aware of these reasons why (there might be others)

  • same-origin security policy
  • Gears won't follow redirects

Comments, bugs

Thanks for reading, any comments are appreciated. My guess is the bug count will be pretty low, due to the fact that when the sh…, er, the bug hits the fan, you'll be offline and cannot report it :)

Now that I'm all set with stuff for offline reading for my short LAX-SJC flight tomorrow, I cannot help but wonder - should I still take with me a plain old reliable hardcopy of a piece of pulp fiction? You know… software breaks :)

 

IE has a problem with getElementsByName

Wednesday, October 3rd, 2007

Yes, it does.

Sometimes it's convenient to use "HTML arrays", meaning to name fields like:
<input name="something[]" />

Then on the server side you loop through the array $_POST['something']

This allows for a flexibility where your app doesn't know the number of inputs in advance, but works fine regardless of the actual number.

Even cooler is that you can generate fields on the client-side, with JavaScript.

The problem is if you want to do some sort of client-side validation after you've generated fields on the fly. If you have:

<input name="something[]" />
<input name="something[]" />
<input name="something[]" />

Then you can access the fields using

document.getElementsByName('something[]')

So in the case above

document.getElementsByName('something[]').length

will give you 3.

Then you add another fields, for example like:

var new_input = document.createElement('input');
new_input.type = 'text';
new_input.name = 'something[]';
document.body.appendChild(new_input);

Now if you try to count the fields with

document.getElementsByName('something[]').length

you'll get 4 in Firefox as you would expect, but still 3 in IE.

Bugs happen, c'est la vie :D

Here's a demo

Tested IE7 only, don't know if the bug exists in earlier versions.

My example was with an HTML array using []s in field names, but the issue remains if you have regular names without brackets, for example you have radio buttons or checkboxes and you want to create more choices dynamically with JavaScript.

 

Make your javascript a Windows .exe

Friday, August 31st, 2007

These days an average web developer needs to have a broad matrix of skills in order to do his/her job. HTML, CSS, JavaScript, AJAX, XML, some server side language, some linux skills, some apache, some database skills, standards, accessibility, SEO, the list goes on. Parts of the list are also multiplied by (or raised to the power of?) the number of browsers you want to support. Crazy, isn't it? We're such optimists trying to make stuff work in such an environment.

There's gotta be an easier way to write code that does something meaningful! Yes, there is, it's called JavaScript. You learn JavaScript, you learn it well, and you don't need to learn anything else. Isn't that cool? JavaScript is, practically, everywhere. Learn JavaScript and you can:

  • create rich and powerful web applications (the kind that runs inside the browser)
  • write server-side code such as ASP scripts or for example code that is run using Rhino (A JavaScript engine written in Java)
  • create rich media applications (Flash, Flex) using ActionScript which is based on ECMAScript, which is JavaScript
  • write scripts that automate administrative tasks on your Windows desktop, using Windows Scripting Host
  • write extensions/plugins for a plethora of desktop application such as Firefox or Dreamweaver
  • create web applications that store information off-line on user's desktop, using Google Gears
  • create Yahoo!, or Mac, or dunno-what-type-of widgets
  • create Windows apps (those that end in .exe) and libraries (.dll)

I'm sure the list above is not even complete.

OK, it's a joke that with one programming skill only you'll be employed for life, but it's a fun thought anyway. Off to the main topic of the post.

JScript

This is Microsoft's version of JavaScript (yep, the thing that annoys us *sometimes* in IE) and can also be used to create server side pages (ASP, ASP.NET) or desktop applications. Apparently JScript is now called JScript.NET and can be compiled to create .exe files. Let's see how.

The compiler

The compiler (program that creates programs) is an exe file called jsc.exe (JScriptCompiler) and is part of the .NET framework. Good news is that you can use it without installing any MS IDE (whatever Visual Studio is called these days), free of charge. Even better, maybe it's already there, on your machine. I searched my completely normal Windows XP machine that doesn't have any special MS tools and was able to find two copies of the compiler! You can search for "jsc.exe" and in case you don't already have it, you can read how to get it here.

So once you find your jsc.exe (found one o' mine in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727), then add this path to your environment path: Right-click My Computer - Advanced - Environment Variables - System Variables - Path - Edit

Now open command prompt (Start - Run - "cmd" - OK) and type "jsc"+ENTER. You should see a list of help options for the compiler. Cool!

First .exe (in years)

The last time I created an .exe file is probably yeeears ago, when I was this Visual Basic king, writing a desktop application that takes a directory of images and creates a web gallery (example)

OK, lets create a simple application.

cd ..
mkdir myapps
cd myapps

Create a file called hello.js with the following content:

var d = new Date();
var n = Math.random();
print('Hello, \ntoday is ' + d + '\nand this is random - ' + n);

Now let's compile!

C:\myapps>jsc hello.js
Microsoft (R) JScript Compiler version 8.00.50727
for Microsoft (R) .NET Framework version 2.0.50727
Copyright (C) Microsoft Corporation 1996-2005. All rights reserved.

No error messages, so we'll take that as an OK ;) Let's check:

C:\myapps>dir
 Volume in drive C has no label.
 Volume Serial Number is B96A-95DB

 Directory of C:\myapps

08/31/2007  07:33 PM    <DIR>          .
08/31/2007  07:33 PM    <DIR>          ..
08/31/2007  07:34 PM             4,096 hello.exe
08/31/2007  07:33 PM               109 hello.js
               2 File(s)          4,205 bytes
               2 Dir(s)  40,287,092,736 bytes free

YES! An .exe was created! Without further ado, let's run it already!

C:\myapps>hello
Hello,
today is Fri Aug 31 19:34:32 PDT 2007
and this is random - 0.5855108083158316

That's so cool, the compiled program works!

Making a DLL

Now, we're convinced that we have a good thing going here, so let's create a DLL, meaning create a library that other applications can use.

JScript.NET has the notion of namespaces and packages (which we usually fake on the web) and class-based objects (eww! well, it supports the prototype stuff as well). So if we simply wrap our code in a package and a class and we create a new file LibHello.js:

package LibHello {
    class Hello {
        function say() {
            var d = new Date();
            var n = Math.random();
            return 'Hello, \ntoday is ' + d + '\nand this is random - ' + n;
        }
    }
}

Let's compile this into a library, we need the /t:library option when compiling

C:\myapps>jsc /t:library LibHello.js

This creates hello.dll and we have a library!

Consuming the lib

Finally, let's create an app that leverages the new library we just created.

Create consumer.js with the following:

import LibHello;
var h = new LibHello.Hello();
print(h.say());

Compile and run:

C:\myapps>jsc consumer.js

C:\myapps>consumer.exe
Hello,
today is Fri Aug 31 19:53:29 PDT 2007
and this is random - 0.45013379838789525

Nice and easy.

So what?

I didn't have time to experiment, but I'm pretty sure you can take tools such as jsmin or jslint and easily compile them into libraries that can be consumed from windows apps, or VBA scripts in Access, Powerpoint, etc. Imagine you're writing some documentation in Word, you select some JS code you just wrote and JSlint it. That would be nice.

BTW, remember how we used /t:library option to produce a .dll and not an .exe? Well, there's also the option /t:winexe which creates a windows application I mean with the window and everything and not a console app. OK, let's give it a shot, create win.js with the following:

import System.Windows.Forms; // this has a MessageBox class
import LibHello;

var h = new LibHello.Hello();
MessageBox.Show(
        h.say(),
        "Dude!",
        MessageBoxButtons.OK,
        MessageBoxIcon.Exclamation
);

Compile:

C:\myapps>jsc /t:winexe win.js

Double click in windows explorer and you have a nice little unquestionably useful Windows application ;)

 

JavaScript: Calling the unnamed

Thursday, August 16th, 2007

How does this look like?

o[""]()

A bit like a syntax error, eh? Or an emoticon of some sort. Well, it's valid JavaScript code.

JavaScript objects can have an empty string as a name for a property/method. So if you create an unnamed method called "", you can't call it using the dot notation, but you can, using the brackets.

So type this in your Firebug console:

var o = {
  "": function(){
        console.log('here')
      }
}

then call the unnamed like o[""]()

It works!

Reminds me of the Wizard of Earthsea a little bit where you had to know the true names of things in order to do the wizardry.

 

Order of execution of event listeners

Tuesday, August 14th, 2007

Say you attach several listeners to an event, for example you want a few things to happen on page load. What is the order of execution of the different listeners? You'd think that the listener attached first will execute first, followed by the second and so on… Well, yes, in FF, Opera, Safari on Windows, but not in IE.

The test

  var i = 1, ol = document.getElementById('result');

  for (i; i <= 10; i++) {
      YAHOO.util.Event.addListener(window,'load',
        function(num){
            return function(){
                ol.innerHTML += '<li>' + num + '</li>';
            }
        }(i)
      );
  }

Result in FF, O, Safari

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10

Result in IE

  1. 1
  2. 2
  3. 4
  4. 6
  5. 8
  6. 10
  7. 9
  8. 7
  9. 5
  10. 3

Observation

Here you can try it out yourself

Try in IE. Reload. Reload again. Notice something? The order is not random. Always starts 1, 2, then goes through all even numbers until 10 then backwards - 9, 7, 5, 3 - all odd numbers.

Try with a bigger loop - still the same thing. Hmm, interesting… Maybe not something you'd like to rely on, but still…