Activate your free membership today | Log-in

Thursday, November 26th, 2009

If That Is An Awesome CSS3 Gallery, How Would You Call Mine?

Category: CSS, Examples

Tutorialzine is a nice blog but I think sometimes it should should re-dimension chosen titles.
I have discovered only yesterday and thanks to my good old favorite Web related italian blog, a nice (or if you prefer another) jQuery lightbox style experiment.

The post is complete with examples and explanation over PHP, CSS, jQuery, and finally jQuery UI.
So what is the problem? The title: An Awesome CSS3 Lightbox Gallery With jQuery

At the end of the day, the total size of the demo is massive, compared with what it offers, plus the only piece of CSS3 in the stylesheet is a box-shadow and a rotation via -webkit-transform.

Is That It?

If we can define awesome a basic usage of CSS3 requiring both jQuery and jQuery UI to create a Gallery, included a server side language, how can we define my latest experiment realized in half an hour and without using JavaScript, PHP, or whatever programming language at all?

The answer is simple: CSS3 and we can read how I did it via the not-minified and hopefully well commented css file.
OK, agreed my page is dynamically fake and a proof of concept, but honestly, which title would consider appropriate for above example?
Thanks in any case to Tutorialzine for the interesting step by step explanation and to let me try above experiment which works with latest WebKit, Chrome, Safari, and somehow with Firefox, I’ve not tried the nightly, and Opera as well but in latter cases without transitions.

P.S. for those with poor computation performances like me, here there is a fluid concept variation ;-)

Posted by webreflection at 6:00 am
23 Comments

++---
2 rating from 55 votes

Wednesday, November 25th, 2009

Javascript JPEG Encoding

Category: Canvas

Andreas Ritter has managed to encode JPEGs in Javascript. This blog post explains how he did it, shows some benchmarks, and provides a demo and a downloadable library so you can play along at home.

It was surprising that it was that easy to get the first js-encoded jpeg displayed in the browser. Of course I didn't want to stop there. I wanted to optimize things as much as I could to make the encoder fast. This took me several days. I found optimized encoder versions for flash and haxe floating around the net (Faster JPEG Encoding with Flash Player 10) and tried the optimizations used there in my javascript version. As you can seen in the benchmarks below I was quite successful.

Another idea was to use the new web workers to do the heavy lifting in an separate thread, not blocking the gui. This is something flash can't do. So I created a version using a web worker for the encoding.

The API gives you a JPEGEncoder or an alternative JPEGEncoderThreaded. Usage is straightforward:

JAVASCRIPT:
  1.  
  2. var myEncoder = new JPEGEncoder([quality])
  3. var JPEGImage = myEncoder.encode(CanvasPixelArray,[quality])
  4.  

I think the results show that JavaScript is quite fast (at least in Safari and Chrome). A little over 4 seconds for the non-threaded version is a very good [sic] result, when compared to the 3,3 seconds the optimized flash jpeg encoder takes. Please note, that JavaScript has no static types, no byte array, no Vector-class and is not pre-compiled. Taking these facts into account Nitro and V8 are faster than the ActionScript 3 VM.

Comparing the different browsers Nitro and V8 are a magnitude faster than TraceMonkey. Firefox 3.6b2 shows some improvements, but it's still a long way. Probably the Mozilla guys should consider adopting Nitro or V8?

He used the AS3 (ActionScript) JPEG encoder as a starting point. It's worth noting there's also a PNGEncoder there too; that's a port waiting to happen.

Posted by Michael Mahemoff at 1:15 pm
10 Comments

++++-
4.7 rating from 25 votes

CBC Radio 3 Case Study

Category: Articles, Editorial, Prototype, Showcase

Phil Rabin of CBC Radio 3 has kindly written a guest post on his experience creating a fantastic Web interface for the station that uses Flash for audio, but a full HTML experience that maintains state from page to page.

cbcradio3

CBC Radio 3 is a community, radio station and user-generated independent music library which is a small department of the Canadian Broadcasting Corporation. When the CBC Radio 3 web team was called upon to rebuild the site we were confronted with the technical problem of having an uninterrupted music experience for our users. The old design of the site (see image) achieved this by embedding a flash player in the body with the content being served through a statically positioned iframe in the center of the page. Radio 3's content offerings were outgrowing the design so we went with a full page 1000px-wide layout with the player resting in the page. This created an obvious hurdle being that with a fresh page load comes a bad listening experience like myspace where a single wrong click breaks the audio. Also, not having popup player was a design decision that was made to give the website a more integrated feel.

We decided to completely removed flash from the UI equation and went full html/ajax because we found that it offered more flexibility and play with the page. The hardest part was figuring out a way to maintain state on each page load while keeping the audio continuous.

We went with an old-school frameset to create a type of inter-frame communication with the top level frameset acting as the orchestrator/bootstrapper. The visible "UI Controller" frame is completely blown out with the stateful player frame hidden from view.

The stateful player frame contains hidden swfs to handle playing audio and connecting to RTMP for our live streaming. All the communication in and out of flash is handled by a couple gateway javascript classes to abstract out the flash from the rest of the application.

Here's an example of a communication gateway for wrapping the events coming to and from flash. The event objects are native flash event objects that get sent by Flash's ExternalInterface and come in as JSON that can:

JAVASCRIPT:
  1.  
  2. CBCR3.namespace("CBCR3.Player.External");
  3.  
  4. CBCR3.Player.External.RTMPGateway = Class.create(CBCR3.Commons.EventDispatcher, {
  5.      
  6.     initialize:function($super)
  7.     {
  8.         $super();         
  9.     },
  10.      
  11.     //Functions to receive events from flash   
  12.     sendStreamEvent:function(event)
  13.     {
  14.         this.dispatchEvent(event.type);
  15.     },
  16.    
  17.     sendMetaDataEvent:function(event)
  18.     {         
  19.         var metaData = new CBCR3.Player.Mappers.StreamMetaDataDtoMapper().mapCollection(event.metaData);       
  20.         this.dispatchEvent(CBCR3.Player.Events.RTMPStreamEvent.metaDataReceived, {metaData:metaData});
  21.     },
  22.        
  23.     //Functions to send commands from flash
  24.     sendStreamCommand:function(commandName, commandArgs)
  25.     {         
  26.         $(CBCR3.Player.Globals.rtmpPlayerId).streamCommand(commandName, commandArgs);
  27.     }
  28. });
  29.  

A single instance of this gateway is always maintained in the application which is called by a sort of simple container like this:

JAVASCRIPT:
  1.  
  2. ExternalInterface.call("CBCR3.Player.Application.IoC.getInstanceOf('rtmpGateway').sendStreamEvent", event);   
  3.  

An instance of the gateway has to be maintained by the player application because events coming from flash have no context. This way the application classes can subscribe to events coming from flash like this:

JAVASCRIPT:
  1.  
  2. CBCR3.Player.Players.RTMPPlayer = Class.create(CBCR3.Commons.EventDispatcher, {
  3.     initialize:function($super, rtmpGateway, thumbLookupService)
  4.     {
  5.         $super();     
  6.          
  7.         this.rtmpGateway = rtmpGateway;       
  8.  
  9.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.metaDataReceived, this.rtmpMetaDataReceivedHandler.bind(this));         
  10.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.ready, this.streamReadyHandler.bind(this));
  11.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.connecting, this.streamConnectingHandler.bind(this));
  12.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.streaming, this.streamStreamingHandler.bind(this));
  13.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.connected, this.streamConnectedHandler.bind(this));
  14.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.metaDataConnected, this.rtmpMetaDataConnectedHandler.bind(this));
  15.         this.rtmpGateway.addEventListener(CBCR3.Player.Events.RTMPStreamEvent.failed, this.rtmpMetaDataFailedHandler.bind(this));
  16.  
  17.  
  18.     },
  19.  
  20.     streamReadyHandler:function(event)
  21.     {
  22.         //handle stream event
  23.     },
  24.  
  25.     streamConnectingHandler:function(event)
  26.     {         
  27.         //handle connecting event
  28.     },
  29.  
  30.     streamConnectedHandler:function(event)
  31.     {
  32.         //handle connected event
  33.     },
  34.  
  35.     rtmpMetaDataConnectedHandler:function(event)
  36.     {
  37.        //handle meta deta connected event
  38.     },
  39.  
  40.     rtmpMetaDataReceivedHandler:function(event)
  41.     {         
  42.         //handle meta data event etc etc
  43.     }
  44. );
  45.  

At the core, audio is always played by Flash. The swfs broadcast events, such as audio head position and download progress of mp3s, and connection, streaming, meta data events from RTMP. Those events get passed on the instance of the hidden stateful player.

Since the server frame is only loaded once when the site first loads, an instance of the stateful server player is instantiated for the entire session on the site. On each client frame page load, the server player instance is "injected" into the visible client UI controller by the "bootstrapper" top frame. State is maintained in that instance which allows for the controller to query the state of that object and reestablish everything like which track is playing, progress, time, thumbs up or down status, shuffle, play mode (stream or individual mp3 and playlists), etc. Everything had to be covered like if an mp3 was in mid-load when someone browsed to a new page, the loading progress had to pickup on the next page. Here's a example of the bootstrapper code contained in the frameset:

JAVASCRIPT:
  1.  
  2. CBCR3.namespace("CBCR3.Player.Application");
  3.  
  4. CBCR3.Player.Application.R3PlayerBootStrap = Class.create({
  5.  
  6.     serverFrame:null,
  7.     clientFrame:null,
  8.  
  9.     autoStart:true,
  10.     permalink:null,
  11.  
  12.     initialize:function(preferences)
  13.     {         
  14.         this.autoStart = preferences.autoStart;
  15.         this.permalink = preferences.permalink;         
  16.     },
  17.      
  18.     setServerFrame:function(serverFrame) {
  19.         this.serverFrame = serverFrame;
  20.     },     
  21.          
  22.     setClientFrame:function(clientFrame) {
  23.         this.clientFrame = clientFrame;         
  24.     },
  25.      
  26.      
  27.     //TRY LOAD PLAYER
  28.     loadPlayer:function()
  29.     {         
  30.         if(!this.clientFrame || !this.serverFrame)
  31.             return;
  32.  
  33.         //both frames are loaded at this point
  34.         if(this.serverFrame.getPlayerInstance() == null)
  35.             this.initializePlayer();
  36.         else
  37.             this.resumePlayer();
  38.     },
  39.      
  40.     initializePlayer:function()
  41.     {
  42.         this.serverFrame.initPlayer();
  43.  
  44.         this.clientFrame.checkEnvironment();
  45.         var masterPlayerInstance = this.serverFrame.getPlayerInstance();
  46.         this.clientFrame.loadPlayer(masterPlayerInstance);
  47.         masterPlayerInstance.addEventListener("stateInitEvent:streamPlayerLoaded", this.streamPlayerLoadedHandler.bind(this));
  48.         masterPlayerInstance.addEventListener("stateInitEvent:playlistPlayerLoaded", this.playlistPlayerLoadedHandler.bind(this));
  49.     },
  50.      
  51.     resumePlayer:function()
  52.     {
  53.         this.clientFrame.loadPlayer(this.serverFrame.getPlayerInstance());
  54.         this.clientFrame.resumePlayer();         
  55.     },
  56.      
  57.     streamPlayerLoadedHandler:function(event)
  58.     {
  59.         if(this.autoStart && this.permalink.include("/stream/"))
  60.             this.clientFrame.getPlayerInstance().stream(this.permalink);
  61.     },
  62.      
  63.     playlistPlayerLoadedHandler: function(event)
  64.     {
  65.         if(this.autoStart && this.permalink.include("/play/"))
  66.             this.clientFrame.getPlayerInstance().playlist(this.permalink);
  67.     }
  68. });
  69.  

We used Prototype/Scriptaculous as the base for the entire site. All the AJAX communication is handled with asp.net web services with scripting enabled. ASP.NET takes care of all the serialization of DTO's (Data Transfer Object) into JSON which are specific to the player application.

All of the classes in the application are written using Prototype's Class/inheritance model. Most of the classes subclass from a base EventDispatcher much like AS3, which is adapted from Matthew Foster's example for Prototype and our own custom Event model. This allows for a nice separation of concerns and decoupled classes throughout the application and allows the UI Controller to add event listeners to custom events coming from the server player instance.

JAVASCRIPT:
  1.  
  2. CBCR3.namespace("CBCR3.Commons");
  3.  
  4. CBCR3.Commons.EventDispatcher = Class.create({
  5.      
  6.     buildListenerChain:function()
  7.     {
  8.          
  9.         if(!this.listenerChain)
  10.             this.listenerChain = {};                                   
  11.      
  12.     },
  13.      
  14.     addEventListener:function(type, listener){
  15.                                    
  16.         if(!listener instanceof Function)
  17.             alert("Listener isn't a function");
  18.              
  19.         this.buildListenerChain();
  20.                  
  21.         if(!this.listenerChain[type])                         
  22.             this.listenerChain[type] = [listener];
  23.         else
  24.             this.listenerChain[type].push(listener);
  25.          
  26.     },
  27.          
  28.     hasEventListener:function(type)
  29.     {
  30.         return (typeof this.listenerChain[type] != "undefined");
  31.     },
  32.      
  33.     removeEventListener:function(type, listener)
  34.     {
  35.         if(!this.hasEventListener(type))
  36.         return false;
  37.      
  38.         for(var i = 0; i <this.listenerChain[type].length; i++)
  39.             if(this.listenerChain[type][i] == listener)
  40.                 this.listenerChain.splice(i, 1);
  41.      
  42.     },
  43.      
  44.     clearEventListeners:function()
  45.     {
  46.         this.listenerChain = {};
  47.     },
  48.      
  49.     dispatchEvent:function(type, data, target)
  50.     {         
  51.         var    event = new CBCR3.Commons.Event(type, data, target || this);
  52.         this.buildListenerChain();
  53.      
  54.         if(!this.hasEventListener(type))
  55.             return false;
  56.      
  57.         this.listenerChain[type].any(function(funct){
  58.             return (funct(event) == false ? true : false);
  59.         });
  60.     }
  61. });
  62.  

This also allows the UI Controller to unsubscribe from all events when the page unloads. This was key in memory management and so that we don't get orphaned references to instances of the UI Controller.

The most difficult part of the whole player project was re-establishing state of the controller on every page load. We hoped that we could implement some sort of state-pattern with no luck. In the end, the UI controller contains a couple monster resume methods that we haven't been able to abstract out of that class. We'd like to bring in some sort of MVC architecture that wires up the UI player view to a state object. Any suggestions would be welcome! Go check out the site and give us some feedback!

Dion: I then asked Phil about the CBCR3 library and he replied

CBCR3 is the base namespace for all th javascript controls and apps written for the site. Everything for the player is in CBCR3.Player, the concert calendar is CBCR3.Gigs, etc. We have a shared base lib which is in CBCR3.Commons.

An issue with Prototype that we had was some bug with including 1.6.1 in a frameset in Opera. So, right now the frameset is holding an older version of prototype while the frames have the latest. One thing that Prototype was seriously lacking was Date extensions. (like addDay, addMonth, addWeek) etc.
We ended up going with YUI's DateMath widget for that which really smoothed out working with dates.

Most of the issues we had cross-browser stuff was with IE6 (no surprise), which were almost all related to CSS rendering bugs, and IE DOM manipulation problems. A big one was upon the dynamic removal of items from lists. IE has a real hard time refreshing the positions of items. We had to write methods like

JAVASCRIPT:
  1.  
  2. myList.select("li").each( function(item){
  3.    li.setStyle({display:"none"});
  4.    li.setStyle({display:"block"});
  5. });
  6.  

this would in effect "nudge" the browser and force it to update the position of the remaining DOM elements. In the end, we chose to drop IE6 support and to tell you the truth, we haven't heard a single complaint about it!

Posted by Dion Almaer at 6:05 am
11 Comments

+++--
3 rating from 19 votes

Tuesday, November 24th, 2009

Node and Djangode Follow-Up

Category: Server

Simon Willison's Talk last week on Node generated a healthy dose of post-conference buzz, and he's followed up with a blog post on Node and his higher-level API for Node, Djangode.

Node’s core APIs are pretty low level—it has HTTP client and server libraries, DNS handling, asynchronous file I/O etc, but it doesn’t give you much in the way of high level web framework APIs. Unsurprisingly, this has lead to a cambrian explosion of lightweight web frameworks based on top of Node—the projects using node page lists a bunch of them. Rolling a framework is a great way of learning a low-level API, so I’ve thrown together my own—djangode—which brings Django’s regex-based URL handling to Node along with a few handy utility functions.

JAVASCRIPT:
  1.  
  2. var dj = require('./djangode');
  3.  
  4. var app = dj.makeApp([
  5.   ['^/$', function(req, res) {
  6.     dj.respond(res, 'Homepage');
  7.   }],
  8.   ['^/other$', function(req, res) {
  9.     dj.respond(res, 'Other page');
  10.   }],
  11.   ['^/page/(\\d+)$', function(req, res, page) {
  12.     dj.respond(res, 'Page ' + page);
  13.   }]
  14. ]);
  15. dj.serve(app, 8008);
  16.  

Pretty simple, and gets a whole lot more interesting when he shows how to build a simple Comet server with this API. He also covers database access, where there's a good fit between server-side Javascript and the NOSQL servers that speak HTTP and JSON.

His article also provides a nice overview of Node itself, along with some straightforward install instructions.

At first glance, Node looks like yet another take on the idea of server-side JavaScript, but it’s a lot more interesting than that. It builds on JavaScript’s excellent support for event-based programming and uses it to create something that truly plays to the strengths of the language.

Node describes itself as “evented I/O for V8 javascript”. It’s a toolkit for writing extremely high performance non-blocking event driven network servers in JavaScript. Think similar to Twisted or EventMachine but for JavaScript instead of Python or Ruby.

Posted by Michael Mahemoff at 9:53 am
Comment here

+++--
3.8 rating from 23 votes

Moving from the Couch to the LawnChair

Category: Database, JavaScript

We have mentioned attempts at doing Couch in the browser before, and now we have a new project.

Brian LeRoux of PhoneGap/Nitobi fame, has taken a lighter couch outside as he announces Lawnchair that aims at being applicable for mobile Web usage (but can of course work anywhere else):

Features

  • micro tiny storage without the nasty SQL: pure and delicious JSON
  • clean and simple oo design with one db table per store
  • key/value store.. specifying a key is optional
  • happily and handily will treat your store as an array of objects
  • terse syntax for searching and therefore finding of objects

Give it a hack:

JAVASCRIPT:
  1.  
  2. // create a store
  3. var people = new Lawnchair('people');
  4.  
  5. // -- adding to the store
  6. // Saving a document
  7. var me = {name:'brian'};
  8. people.save(me);
  9.  
  10. // Saving a document async
  11. people.save({name:'frank'}, function(r) {
  12.     console.log(r);
  13. });
  14.  
  15. // Specifying your own key
  16. people.save({key:'whatever', name:'dracula'});
  17.  
  18. // -- Getting content out
  19.  
  20. // Get that document
  21. people.get(me.key, function(r){
  22.     console.log(r);
  23. });
  24.  
  25. // Returns all documents as an array to a callback
  26. people.all(function(r){
  27.     console.log(r);
  28. });
  29.  
  30. // List all with shortcut syntax
  31. people.all('console.log(r)');
  32.  
  33. // -- Removal
  34.  
  35. // Remove a document directly
  36. people.get(me.key, function(r){
  37.     people.remove(me);
  38. });
  39.  
  40. // Remove a document by key
  41. people.save({key:'die', name:'duder'});
  42. people.remove('die');
  43.  
  44. // Destroy all documents
  45. people.nuke();
  46.  

Posted by Dion Almaer at 6:20 am
7 Comments

+++--
3 rating from 7 votes

Monday, November 23rd, 2009

Zen Coding: Generating HTML from selectors

Category: HTML, Utility

Normally we use CSS selectors to find and tear apart HTML. Sergey Chikuyonok's jujitsu move is to do the opposite. With Zen Coding you take a CSS selector like this:

HTML:
  1.  
  2. html:xt>div#header>div#logo+ul#nav>li.item-$*5>a
  3.  

and it generates an HTML structure like this:

HTML:
  1.  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  4.         <title></title>
  5.         <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  6. </head>
  7.         <div id="header">
  8.                 <div id="logo"></div>
  9.                 <ul id="nav">
  10.                         <li class="item-1"><a href=""></a></li>
  11.                         <li class="item-2"><a href=""></a></li>
  12.                         <li class="item-3"><a href=""></a></li>
  13.                         <li class="item-4"><a href=""></a></li>
  14.                         <li class="item-5"><a href=""></a></li>
  15.                 </ul>
  16.         </div>
  17. </body>
  18. </html>
  19.  

You can check out a demo or try out support in various editors (Aptana to TextMate).

Now I want to create a Bespin plugin to do this too!

Posted by Dion Almaer at 6:45 am
11 Comments

++---
2.9 rating from 10 votes

New SVG Web Release: Gelatinous Cube

Just in time for Thanksgiving is another SVG Web release. The SVG Web project's tradition is to name SVG Web releases after monsters from D&D just to increase the geek factor, so in that spirit their release name this time is "Gelatinous Cube":

The Gelatinous Cube is a truly horrifying creature:

A gelatinous cube looks like a transparent ooze of mindless, gelatinous matter in the shape of a cube. It slides through dungeon corridors, absorbing everything in its path, digesting everything organic and secreting non-digestible matter in its wake. Contact with its exterior can result in a paralyzing electric shock, after which the cube will proceed to slowly digest its stunned and helpless prey.

Fun times.

Highlights of this release:

  • Loads of important bugs fixed
  • Performance improvements
  • You can now dynamically create new SVG root tags
  • All the namespace aware functions now implemented: setAttributeNS, getAttributeNS, etc.
  • You can now clone SVG nodes (cloneNode)
  • You can now right-click on the SVG when using Flash to view the dynamic updated SVG source
  • Running getElementsByTagNameNS scoped to a particular node now works, such as myGroup.getElementsByTagNameNS(svgns, 'text')
  • and much much more

Read more about the new release.

Learn more about SVG Web:

About SVG Web and SVG:

SVG Web is a JavaScript library which provides SVG support on many browsers, including Internet Explorer, Firefox, and Safari. Using the library plus native SVG support you can instantly target close to 100% of the existing installed web base. SVG itself stands for Scalable Vector Graphics, an open standard that is part of the HTML 5 family of technologies for interactive, search-engine friendly web vector graphics.

Posted by Brad Neuberg at 6:15 am
Comment here

+++++
5 rating from 4 votes

Friday, November 20th, 2009

Full Frontal ‘09: Simon Willison on Server-Side Javascript and Node.js

Category: JavaScript, Server

Simon Willison snuck in a last-minute topic change, and is now going to give the server-side Javascript talk.

The news of the past 24 hours is ChromeOS. For the first time in years, someone's re-thinking how an OS should work. With Chrome, you turn on your computer and you're in the browser. What's really interesting is to contrast it to the introduction of the iPhone, where Apple's apps used native APIs while they expected developers to write web apps running in the browser with limited abilities. Here, Google's apps are using the same web platform...it's a level playing field.

Javascript combined with JSONP makes it real easy to write quick and dirty apps. An example of a quick app is Tweetersation Simon wrote with Natalie Downe. Simple app, 200 lines, written in an afternoon. At a larger system level, there's Google Moderator, which is essentially a pure-Javascript solution with a no-op in the noscript tag.

These pure Javascript apps are great for experimenting and prototyping. The problem with this style of development, though, is you're completely breaking web standards. The web Simon "felll in love with" is one where you point to a URL and you get content coming back.

With server-side Javascript, we can get the benefits of the things we like about Javascript, but without throwing away with the things we like about the web. Simon has been playing with node.js, and evidently the results were important enough to throw out the old talk and make this new one.

Take a step back and look at the interaction patterns with a web server. The conventional model is straightforward request-response, where the server tries to respond and disconnect as quickly as possible. But ... there's also the event loop model. As in Comet; it's generally considered to be more efficient, so why do web developers avoid it? Simon says traditional server-side languages aren't designed to deal with event-driven programming. It's more like "do A, do B, do C, exit". Javascript, on the other hand, is well suited to do callback-driven event programming.

Brave Simon now proceeds to live code with node.js. He shows a "Hello World" daemon, where the code looks like Ajax in reverse, and runs extremely fast. But where it gets really interesting - and useful - is with Comet. Another demo. The code is tiny and the benchmark looks good.

Simon's built his own framework on top of node.js: Djangode takes the best features from Django and sticks them on the server.

JAVASCRIPT:
  1.  
  2. var dj = require('./djangode');
  3. dj.serve(dj.makeApp([
  4.     ['^/$', function(req, res) {        dj.respond(res, '<h1>Homepage</h1>');    }],    ['^/other$', function(req, res) {
  5.         dj.respond(res, '<h1>Other page</h1>');
  6.     }],
  7.     ['^/page/(\\d+)$', function(req, res, page) {
  8.         dj.respond(res, '<h1>Page ' + page + '</h1>');
  9.     }]
  10. ]), 8008); // Serves on port 8008
  11.  

The more interesting example is Comet, which he's demo'd here.

Moving on to persistence, there's the NOSQL trend of the past 18 months, and he shows how simple it is to write CouchDB queries from node. It's easy to talk to CouchDB from Node.js apps. Redis is another interesting database, which could lead to pages being rendered very quickly, given its performance benchmarks.

Posted by Michael Mahemoff at 12:41 pm
Comments Off

+++--
3.1 rating from 28 votes

Full Frontal ‘09: Jake Archibald on Performance Optimisation

Category: Performance

Jake explains no-one likes waiting, and people are multi-threaded (except when they have to sneeze). Yet, we're stuck with a single-threaded language for the most part; and we still face the legacy of a DOM standard from another era (DOM Level 1 - 1997). This talk provides some optimisation tips, backed by Jake's cross-browser experiments.

Jake's slides and research are online.

Optimise Where it Matters

Jake explains the importance of speeding things up where it really matters.

Doug Crockford has pointed out that in Javascript, bitwise operations aren't close to the hardware, which stands in contrast to other languages. In fact, if you look at it, bitwise operations can still be faster than alternative operations; Jake shows an example where bitwise parsing of hex codes is faster than bitwise. The question is, how much faster? In many cases, such as this example, your energy is better spent on optimising big things.

Avoid eval() Where Possible

Jake says avoid eval() where possible. Thinking about what functions eval, here's a brain teaser: what will the following output?

JAVASCRIPT:
  1.  
  2. var msg = "spatchcock";
  3. function doStuff() {
  4.   alert(msg);
  5.   if (false) {
  6.     var msg="spotted dick";
  7.   }
  8. }
  9. doStuff();
  10.  

Wait for it ... the answer is "undefined". Javascript does look ahead and create space for the local variable. So during the running of the function, there's no need to allocate space for the variable and the browser can optimise for that, but if you use "eval", the optimisation goes away. So avoid eval().

Prefer innerHTML to DOM

Jake shows a comparison of innerHTML versus DOM Level 1. In IE, DOM manipulation is much slower, because of the sync process between the two. The differential gets even worse when creating elements. Webkit has optimised sync between HTML and DOM, hence less difference, so it's not as bad, but create example is still slower with DOM. So from a performance perspective, best practice is construct the HTML and use innerHTML.

Selectors

It's educational to look at the implementation of selector libraries. Jake shows a comparison - IE7 is vastly more slow in this case. It doesn't support getElementsByClassName, querySelectorAll, evaluate; and it does support getElementById, but that's not used by sizzle for this query. So getElementsByTagName is all that's left; and if you knew that, and the implications, you could have made the query much faster.

Benchmarking

Pretty simple.

JAVASCRIPT:
  1.  
  2. var duration;
  3. start = new Date()
  4. thingToTest();
  5. duration = new Date() - start;
  6.  

However, timing isn't so accurate, so stick it in a function and run it many times.

Too easy ... so go benchmark and report your findings.

Posted by Michael Mahemoff at 12:11 pm
13 Comments

++++-
4.2 rating from 20 votes

Full Frontal ‘09: Todd Kloots on ARIA and Acessibility

Category: Accessibility, HTML, Usability

Todd Kloots is talking accessibility and ARIA, with examples showing how YUI nicely supports these techniques. He explains how to improve in three areas: perception, usability, discoverability.

Can We Do ARIA Today?

Yes.

Firefox and IE (he didn't say which version) have really good support for ARIA. And Opera, Chrome, and Safari. Likewise for the screenreaders - JAWS, Windows Eyes, NVDA - also have good support. An the libraries - YUI, Dojo, JQuery-UI - all have good support baked in, one of the benefits of using ARIA is automatic support.

Improving Perception - ARIA and Screenreaders

Websites can have problems in perception when rendered with a screenreader; it's hard to get the big picture about what the words refer to. With ARIA, we can close the gap in perception. This is another example of progressive enhancement - augment the item by adding properties, markup or Javascript if required:

JAVASCRIPT:
  1.  
  2. node.setAttribute("role", "menu")
  3. node.role = "menu" // alternative introduced by IE8. IE-only, so don't use!
  4.  

Improving Usability - Keyboard Focus, ARIA, and YUI support

Keyboard access. For some people, it's a necessity, and for others it's still an option or preference (think Vim). To support it, you must be able to tab to the element to get focus, so you should control tabbing with tabindex. A good application of controlling tabbing is, amazingly enough, moving through tabs. Another is modal dialogs; the browser doesn't "know" it's modal, so we have to control focus to make sure it doesn't slip out of the thing that's the only thing users should be able to click on!

Todd shows us just how many steps are required to perform a task in a complex application like Yahoo! mail, using just tabs to navigate through - 19 steps in this example, walking through the toolbar; and even more, when you consider the wider picture of entering the app in the first place. To help with this, he introduces a pattern whereby tabIndexes are updated dynamically to control what comes next, as you move through a toolbar. A negative tabIndex will ensure the element is skipped over.

You can also use the "focus" pseudoclass to ensure focus appearance is consistent for all elements. But, and it's a big one, it's not very well supported; even IE8 doesn't support :focus on <a>, for example. Doing it manually with Javascript has problems, in particular performance. Fortunately, PPK has worked out how to handle focus and blur with event delegation, so that it's much more performant, and the resulting technique is built into YUI3.

Device-independence with markup was also advocated to further improve accessibility:

HTML:
  1.  
  2. <input role="menuitem" type="text/>
  3.  

Improving Discoverability - ARIA

Essentially, this is about "random access" and keyboard shortcuts; jumping straight to areas in this page and activating them. The key ARIA feature here is "landmark roles" to identify particular points on the page. This is still something where users aren't aware of the feature, and Todd points out it's not surprising as most screen reader users are self-taught (just under 75% according to the study he showed). Also, not every user is a geek, and the same applies to screen-reader users.

Posted by Michael Mahemoff at 11:10 am
2 Comments

+++--
3.8 rating from 12 votes

Full Frontal ‘09: Stuart Langridge on HTML5 Features

Category: IE, JavaScript, Presentation

Stuart Langridge introduces us to some of the up-and-coming features we're getting with current and future browsers, a nice complement to Robert Nyman's talk, which covered the advanced features of "mainstream" (IE6-compatible) Javascript. After introducing the features that are there today, he also talks about how we can deal with the browser many of us are still having to support.

The Goodies

Here are some of the things we can look forward to. (Having been part of the large crowd who charged the pub across the road at lunch, I was a bit late getting back, so I missed one or two of these.)

Lists

JAVASCRIPT:
  1.  
  2. [1,2,3].every(function()) // run for all items
  3. list.filter() // find elements in the list that pass the function
  4. list.map() // apply function to each item
  5.  

It takes a mental shift to start taking advantage of features like this. "Certain browsers" *cough* don't yet provide these conveniences, but you can take advantage of them straight away. Or another example is the base2 library - use it now and you'll be ready for the time when it's present in all browsers.

Getters and Setters

As our Javascript apps get increasingly bigger and more complex, we need to borrow principles, patterns, and techniques from "real programming". Getters and setters are the kind of thing we'll need more of. More generally, we'll need to be in the mindset that we're building APIs to components, which others might use; not just an individual making a one-off web app. Stuart shows a couple of techniques for getters and setters: (a) manually defined; (b) using

Storage

We can now do global storage - globalStorage works similarly to cookies. "Like cookies turned up to 11".

JAVASCRIPT:
  1.  
  2.   globalStorage["kryogenix.org"].visits = visits+1
  3.  

He notes that like XHR, Microsoft did it a long time ago with userdata.

There is also the possibility of SQL and a consistent database API, somewhat supported today but not yet standardised.

Server-Sent Events

HTML:
  1.  
  2. <event -source src="getTime.php">
  3.  
JAVASCRIPT:
  1.  
  2. document.getElementsByTagName("event-source")[0].addEventListener("server-time", eventHandler, false);
  3. function eventHandler(event) {
  4.   alert(event.data);
  5. }
  6.  

Only in Opera right now.

Great. So Do We, Can We, Use it Now or Later?

You can use these features now if you're in a single-browser environment that supports them: app for one mobile; Air app; intranet app (where you've amazingly got Firefox exlcusively on your intranet); HTA. This isn't the sinful act of coding to weird proprietary APIs; it's coding to browsers that happen to support the technologies of tomorrow, today.

The libraries help us get to the future today, as long as they can support APIs compatibly across all the browsers. But it's all a little difficult when the market leader doesn't play ball. Hopefully, Dean Edwards will continue working on Base2 to plug the gaps, but we still have the problem. Around a year ago, it felt like the anti-IE6 might be at a tipping point, but that's died down a bit, and it's not clear how much longer we'll be held back.

What can you do then with IE6? If a number of major websites really held back and stopped supporting IE6, Stuart reckons corporations would upgrade. Imagine what would happen if Google stopped working on IE6...immediate upgrades. Show of hands indicates perhaps 20% of the audience would agree to mass dropping IE6 on their public sites. In Q&A, Stuart later clarifies he's not really proposing an IE6 shutdown switch, more like a helpful suggestion to upgrade.

Silverlight and Flash. Proprietary, not open. If everyone started using Flash, the future is Adobe's future. Let's make it our future instead - we're building the open web. A call to arms for showing strength in numbers.

Posted by Michael Mahemoff at 10:52 am
1 Comment

++++-
4.2 rating from 12 votes

Full Frontal ‘09: PPK on Mobile Quirks and Practices

Category: JavaScript, Mobile

PPK talks up the excitement of mobile web development, then brings the mood down a notch by listing the overwhelming array of browsers to be targeted! Quirksmode says it all. This talk is about quirks in mobile development, and some of the solutions out there.

Mobile CSS Quirks

So many platforms. Take just WebKit; there's iPhone Safari, Android WebKit, Bolt, Iris, different versions, etc. "If someone says my 'app should work in WebKit', laugh in their face. There are just too many versions of WebKit, so as PPK says it, there really is no "WebKit for mobile".

That said, it's good that things are starting to converge towards WebKit. As for the others: Blackberry browser "is dead" as they'll be switching to WebKit; Mozilla is very late to the game; NetFront "is not very good". Windows Mobile 6.5 is a big improvement on 6.1, and with an improved browser, but it's still IE6 based. ('Nuff said.)

There's also a large legacy share, and if users are used to it already, that may be what they want to keep using.

Landscape versus profile mode is an interesting one for those of us desktop developers whose users don't flip their heads around on a regular basis. NetFront has some very surprising and idiosyncratic ways of dealing with it.

The modes don't stop there. There is also mobile versus desktop mode in some browsers; sometimes users can switch these in some obscure corner of their mobile browser preferences. Again, some surprising things happen in Opera and Android. Perhaps of more concern is the difficulty he had diagnosing the situation at first, when Android was showing three divs of the same width in one mode, and not in the other.

@media to the Rescue

Okay, what can we do about all this? Media queries are extremely useful and fairly well supported in modern mobile browsers.

CSS:
  1.  
  2. div.sidebar {
  3.   width: 300px;
  4.   float: right;
  5. }
  6.  
  7. @media all and (max-width: 400px) {
  8.   div.sidebar {
  9.     width: auto;
  10.     float: none;
  11.   }
  12. }
  13.  

max-width and min-width have subtle issues which PPK is currently researching, but max-device-width and min-device-width give more reliable results. orientation, aspect-ratio, and dpi (also needs research).

Mobile Javascript

Performance-wise, IE Mobile and Blackberry extremely slow. iPhone is middle ground. The really fast browsers are Opera on Samsung and N97, and S60 on Nokia E71 and N97. The bottom line is take your time with mobile Javascript development; you generally can't expect it to "just work"; you'll have to optimise. Also, don't use iframes - they're major performance hogs.

Mobile Connections

Tempting fate, PPK informs us that if someone in the room starts downloading movies, the network gets slower for the rest of us.

Fortunately, browsers give us events to determine when user is going online and offline. Unfortunately, they're doing it wrong. Only Firefox automatically detects offline; all the others require the user to explicitly say "I'm offline now"!

W3C Widgets

In general mobile development, best practice is to put all the core files on the moble phone, and only download the data. But how can we do that with web apps, where the code comes down with the data? W3C widgets offer a solution. You just create a single HTML page with the CSS, Javascript, and images you need; add an icon and config; zip it up; and deploy. PPK reports it works in practice, and works in a "write once, run many" fashion. There are still problems to be sure, but he says it's the best interoperable solution we have today. But still many outstanding platforms: Blackberry (already talking about it), Nokia Maemo, Palm Pre, Android, and of course, iPhone.

Device APIs

Security risks mean critical device APIs will generally remain off limits to general websites for a while. Widgets have a better model, because they're more self-contained and can be verified, although not perfect either.

Posted by Michael Mahemoff at 7:58 am
Comment here

++++-
4.3 rating from 11 votes

Friday Fun; Scroll Clock

Category: Fun, MooTools

This is in the crazy but fun category, so I had to post this on a Friday. Toki Woki Scroll Clock:

scrollclock

Amazing what folks do with div overflows :)

All in a few lines of MooTools-used-JS:

JAVASCRIPT:
  1.  
  2. var h1, h2, m1, m2, s1, s2;
  3. window.addEvent('domready', function() {
  4.         h1=new Digit();
  5.         h2=new Digit();
  6.         m1=new Digit();
  7.         m1.pushRight();
  8.         m2=new Digit();
  9.         s1=new Digit();
  10.         s1.pushRight();
  11.         s2=new Digit();
  12.         $('main').adopt(h1.getElement(), h2.getElement(), m1.getElement(), m2.getElement(), s1.getElement(), s2.getElement());
  13.         showTime();
  14.         setInterval('showTime()', 1000);
  15. });
  16. function showTime() {
  17.         var now=new Date();
  18.         h1.show(now.getHours()/10);
  19.         h2.show(now.getHours());
  20.         m1.show(now.getMinutes()/10);
  21.         m2.show(now.getMinutes());
  22.         s1.show(now.getSeconds()/10);
  23.         s2.show(now.getSeconds());
  24. }
  25. var barDim=120;
  26. var sbDim=18;
  27. var Bar = new Class({
  28.         initialize: function(dir) {
  29.                 this.dir = dir;
  30.                 var dim=dir=='v' ? barDim : (Browser.Engine.gecko ? barDim : barDim+sbDim);
  31.                 this.holder=new Element('div', {styles:{width:dir=='h' ? dim : sbDim, height:dir=='h' ? sbDim : dim, overflow:'auto', float:'left'}});
  32.                 this.content=new Element('div', {html:'&nbsp;'});
  33.                 this.activate(true, true);
  34.                 this.holder.adopt(this.content);
  35.         },
  36.         activate:function(b, now) {
  37.                 var side=this.dir=='h' ? 'width' : 'height';
  38.                 if (now) this.content.setStyle(side, b ? barDim+sbDim : barDim/2);
  39.                 else this.content.tween(side, b ? barDim*2 : barDim/2);
  40.         },
  41.         getElement:function() {
  42.                 return this.holder;
  43.         }
  44. });
  45. var HBar = new Class({
  46.         Extends: Bar,
  47.         initialize: function(){
  48.                 this.parent('h');
  49.                 this.holder.setStyles({'margin-left': sbDim, 'margin-right': sbDim});
  50.         }
  51. });
  52. var VBar = new Class({
  53.         Extends: Bar,
  54.         initialize: function(){
  55.                 this.parent('v');
  56.         },
  57.         pushRight:function() {
  58.                 this.holder.setStyle('margin-left', barDim);
  59.         }
  60. });
  61. var Digit=new Class({
  62.         initialize: function() {
  63.                 var holder=this.holder=new Element('div', {styles:{width: barDim+2*sbDim, float:'left', 'margin-right':20}});
  64.                 this.bars=[new HBar(), new VBar(), new VBar(), new HBar(), new VBar(), new VBar(), new HBar()];
  65.                 this.bars[2].pushRight();
  66.                 this.bars[5].pushRight();
  67.                 this.bars.each(function(it) {holder.adopt(it.getElement());});
  68.                 this.lights=[
  69.                         [1, 1, 1, 0, 1, 1, 1],//0
  70.                         [0, 0, 1, 0, 0, 1, 0],//1
  71.                         [1, 0, 1, 1, 1, 0, 1],//2
  72.                         [1, 0, 1, 1, 0, 1, 1],//3
  73.                         [0, 1, 1, 1, 0, 1, 0],//4
  74.                         [1, 1, 0, 1, 0, 1, 1],//5
  75.                         [1, 1, 0, 1, 1, 1, 1],//6
  76.                         [1, 0, 1, 0, 0, 1, 0],//7
  77.                         [1, 1, 1, 1, 1, 1, 1],//8
  78.                         [1, 1, 1, 1, 0, 1, 1] //9
  79.                 ];
  80.         },
  81.         show: function(n) {
  82.                 n=Math.floor(n);
  83.                 n=n%10;
  84.                 var light=this.lights[n];
  85.                 this.bars.each(function(it, index) {
  86.                         it.activate(light[index]==1);
  87.                 });
  88.         },
  89.         pushRight:function() {
  90.                 this.holder.setStyle('margin-left', '50px');
  91.         },
  92.         getElement:function() {
  93.                 return this.holder;
  94.         }
  95. });
  96.  

Posted by Dion Almaer at 7:35 am
7 Comments

++++-
4.7 rating from 39 votes

Full Frontal ‘09: Robert Nyman on the Javascript Language

Category: JavaScript, Presentation

Robert Nyman walks through some of the more subtle low-level features of Javascript, and some of the idioms that have emerged.

Comparisons: Understanding identity (===) versus equality (==).

Boolean expressions: Understanding how short-circuit logic (if a && b won't eval b if a is false);

Types: Type coercion ("1"+2+3); "falsey" (false, null, 0) versus "truthy"; the importance of using operators like parseInt and instanceof.

Functions: Anonymous functions; self-invoking functions - function() { })() ; using the arguments collection to get all arguments to the current function, important to note it's not a real array with all the array methods, and using arguments to overload arguments.

Objects: Using object literal notation { a:b, c:d } instead of setting up properties individually; equivalence of ben.arms and ben["arms"], and how useful it can be to use the latter in conjunction with a function argument, ie let the caller pass in a variable which will be set; using "in" to check if a property exists (if "arms" in ben).

Inheritance: Using the prototype chain for inheritance from subclass to superclasses up to Object. There are various implementations - e.g. Resig, Edward's Base, Dan Webb; if you understand these implementations, then you understand Javascript. However, Robert's arguing for the native way of doing it - as Doug Crockford says, "I now see my early attempts to support the classical model in Javascript as a mistake".

Global scope: Avoid using global scope where you can. For example, nesting functions. R
obert later points to the Yahoo! module pattern.

Binding this: Using call and apply; these are useful for setting this and also can pass arguments through from the current function to another one without having to manually copy them out.

Sugaring: Adding syntax sugar, e.g. extending String.prototype.

Currying: As illustrated by Doug Crockford's curry implementation.

Posted by Michael Mahemoff at 7:06 am
4 Comments

+++--
3.5 rating from 14 votes

Full Frontal ‘09: Chris Heilmann on Javascript Security

Category: JavaScript, Security

It's another Javascript conference! Full Frontal has kicked off in Brighton this morning (fullfrontal09 on twitter). First up is Ajaxian and Yahoo Chris Heilmann on Javascript security. The main theme is let's use Javascript sensibly and don't just blame the language when other things are creating the risks too.

Chris walks us through the history of javascript. The days of building complex systems with document.write() are over thankfully, though some people still think that's what it's all about. Having annoyed people with all the js bling, Ajax came around and suddenly javascript is seen as a tool for useful stuff. But...a little too much Ajax perhaps? People using it where it didn't need to be and how it shouldn't be used, hence the security fears.

According to a pie chart Chris presents, browser problems are responsible for only 8% of vilnerabilties; the biggest problems are SQL injection and XSS, where the server should be locking down.

Don't judge the language by its implementation. it does have intrinsic issues like global variables, but the right implementation can keep things secure. As well as poor practice, the browsers bear responsibility. And the cool kids - safari and firefox - are the most vulnerable according to this survey. And it gets a lot worse when you start playing with browser extensions.

So do we turn javascript off? No, the experience of google maps etc is just too good. We don't have to learn just by "View Source" anymore. There are plenty of resources out there to learn how to do it and how to do it properly (not just with a magic code-gen tool). Use javascript for the right things, not all things. e.g. Slicker UI, data validation warnings, UI controls not native to HTML, visual effects not native to CSS.

What if you're sharing content from third parties, as the yahoo homepage now allows? Caja is presently the only way to do sandboxing in the browser. It doesn't output pretty code right now, but it does cut out many risks. Caja prohibits eval(), iframes, * and _ hacks, an many other dangerous features. The latest YUI is caja-compliant code, and Chris reports John Resig is open to the same thing for jQuery, if it turns out there is demand out there.

Chris presents various examples of Javascript outside the browser - Air, web widgets, server side, even TV sets. It's a very useful tool here, and shows it doesn't have to be limited to the browser and the security risks that come with browsers.

Posted by Michael Mahemoff at 6:00 am
Comment here

++---
2.9 rating from 12 votes

Thursday, November 19th, 2009

NGiNX HTTP Push Module

Category: Comet

Even PHP developers can write web applications that use all sorts of fancy long-polling.

That is what Leo said about his NGiNX HTTP push module:

This module turns Nginx into an adept HTTP Push and Comet server. It takes care of all the connection juggling, and exposes a simple interface to broadcast messages to clients via plain old HTTP requests. This lets you write live-updating asynchronous web applications as easily as their old-school classic counterparts, since your code does not need to manage requests with delayed responses.

NHPM fully implements the Basic HTTP Push Relay Protocol, a no-frills publisher/subscriber protocol centered on uniquely identifiable channels. It it an order of magnitude simpler and more basic than similar protocols (such as Bayeux). However, this basic functionality together with the flexibility of the server configuration make it possible to reformulate most HTTP Push use cases in Basic HTTP Push Relay Protocol language with very little application- and client-side programming overhead.

Configure NGiNX and write some code to talk to it.

Posted by Dion Almaer at 6:15 am
5 Comments

++++-
4.2 rating from 24 votes

Next Page »