My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Saturday, May 28, 2011

My Last Comments On JSLint

Preface

I have been working with many teams and I have used JSLint on daily basis. This post is not about the tool itself, neither against Douglas work, this post is about developers often too religious about this tool.
Finally, if you follow this blog you have already read tons of other reasons to think rather than "suffer silently this tool".
It's my last post about it and I hope "it will not hurt your feelings".


Seriously guys, it's not that I think JSLint is all bad, but I cannot stop thinking it's simply an effect.
The more I hear or read about developers being so religious about this tool, the more I feel to blame it.
I am pretty sure Douglas will hate me for this post but I really hope he will read it 'till the end.

Douglas Talk At Falsy Values

Both me and big Doug were there, me for a workshop and Mr D. for his speech.
"Surprisingly" Mr Crockford talked about JSLint (again?!) and why it's so good.
While many hints for newcomers are absolutely a must know, many others are absolutely inconsistent for senior JavaScript developers.
There is a particular slide and a particular sentence Douglas said there:
... write code the way it's meant for the language ...

Above sentence was related to variables declaration, showing behind something similar to this classic example:

(function () {
// never executed
if (false) {
var something = 123;
}
}());

As all of us know, and if not we should, the reason JSLint would like to have all variables defined on top of the function is that no matter which condition, for or while loop, we have at some point, the parser will pre-consider all var in the same scope as local scope variables available since the very beginning.

(function () {
// there is no "var" in this scope
alert(something);
// throws "Can't find variable: something"
if (false) {
// eventually global in ES3 and ES5 with no strict
something = 123;
}
}());

The moment we define a variable local, even if we never reach that line, that variable is available for the whole scope, got it?

(function () {
alert(something);
// undefined and no errors
if (false) {
var something = 123;
}
}());

Good, now ...

JSLint Inconsistencies

Since the previous point is clear to everybody, I wonder if it's clear that function declaration has even more precedence than variables.

(function () {
alert(something);
// the function declared later on

function something() {
return 123;
}
}());

This is not true for function expressions, where the result will still be the same obtained with variables:

(function () {
alert(something);
// undefined and no errors

var something = function() {
return 123;
};
}());

Accordingly, function declaration is referenced on top of everything, variables included!
So why on bloody earth this piece of code does not pass JSLint?

var something = (function () {

// top reference available ever
// function declaration
function something() {
return oneTwoThree;
}

// second references available in this scope
// local scope variable
var oneTwoThree = 123;

// return the local function call
return something();

}());

Try by yourself the result:

Error:
Implied global: oneTwoThree 5

Unused variable: oneTwoThree 1 'something'

---------------------------------

Global something

1 'something'()
Unused oneTwoThree
Complexity 1

4 something()
Global oneTwoThree
Complexity 1

I can bet the amount of bullshit I can read in latter result is a shame for Douglas Crockford in first person, isn't it?

Not Only Inconsistencies

Another part covered by Doug speech was the with statement ... here summarize:

... somebody (n.d. I guess me) may argue that the with statement may be useful in certain situations, but since it is always ambiguous and there is nothing that could not be done without it, the with statement should disappear from JavaScript ....
... and this is what happened.
If we try "use strict"; activation in most recent browsers we can spot that the with statement is not allowed anymore, "thanks"!

A Tool To Rule Them All

It was actually a colleague of mine asking Douglas this question (or what I got about it) :

... so, you are saying that JS developers have no discipline, but don't you think that "dictating discipline" is not such easy task as well? ...
I honestly do not remember the answer but I am sure Douglas provided a proper one ... anyway ... what I do believe is that every developer has is own style, as long as syntax and readability are not too much compromised.
If we use this tool thinking our code will improve any how we are first of all acting like machines plus we are not considering a "little detail" ...

Your Team Does Not Know JavaScript

Precisely! I know this is hard to face, but in 11 years of JavaScript programming I have never found a reason to have such tool that changes allowed programming language syntax defined by specifications ... fucking read them and stop winging! (and pardon my french)
In few words, I have never had a single problem to understand any other piece of JavaScript code written by any possible developer out there but when I had a problem, and at the beginning of whatever programming language we all have, I have investigated, studied, and finally understood, what was going on in that piece of code and what was missing from my JS knowledge about it.
Surely I did not blame the other developer, since if we would like to be monkeys on daily basis, of course we should use as many tools as possible that throw warnings even if the piece of code we wrote is absolutely correct, and we still have my precedent example few paragraph before as proof ...
On the other hand, if we would like to master our JavaScript knowledge there is no way a piece of code that perfectly works could be screwed up because of JSLint.

Early JavaScript Days

When Douglas Crockford was still promoting JavaScript all over the world, nobody had any idea what he was talking about ... well, now we all have.
This bloody language is absolutely everywhere and those "feeling cool" Java developers that still think JS is a toy are regretting 50% of their studies because they just don't get it ... that's why projects like GWT exists: developers that think JavaScript is a toy, write Java that is gonna be translated into Javascript ... and this is how powerful and flexible JavaScript is.
In these days, and surely before, we truly need discipline and a lot of hints since as lazy developers we could not spend half a day reading ECMAScript 3rd Edition specs ... isn't it?
In these days, and for these developers, of course JSLint has to be there, they don't know what they are doing but hey, at least they are willing to learn something more from this tool (and most likely behind a syntax translator such GWT is, created to do not throw JSLint warnings ...) .
As demonstrated before, this is not enough.
Java skills into JavaScript language are similar to me pretendng to have Alex Martelli knowledge using Visual Basic 6 on daily basis ... I hope you know what I mean ...
As summary, if you think you can move knowledge from another programming language without deeply understanding the new one pretending you come from "something better" you are half way trough your own failure.
At the end of the day it may not matters, as long as the next point is clear for everybody.

TDD And Unit Tests Are The Only "Safer Way"

Yeah you read it right ... there is no way our JavaScript code is gonna be any safer because of JSLint or whatever JS validation tool: no fucking way!
If we think that === rather than == is all we need to be safe, without understanding why we may be safer or why we may do something simply redundant without considering cases where we want to ==, we have never been so wrong.
Unit Tests, and more Unit Tests on top of Unit Tests are the only answer to our code quality!
It does not matter how we write routines as long as real Senior Developers can understand it, simply asking more if they really don't, and as long as all our possible implementation cases have been considered.
If we are those kind of "my code pass JSLint, my code is better and safer and cleaner" develoeprs, we are simply demonstrating how much we still have to learn about programming.
I don't know any other language that religious or with need of these kind of "natural programming code evaluation tools" and we all know JavaSscript is not the first programming language ever, neither the last one.
If it's about some common code convention we don't need JSLint, we simply need a bloody wiki/web/infrastructure page able to explain it so that somebody else could eventually blame it the moment he's flexible enough to understand meant edge cases.
This is what I have answered as well during my workshop when somebody asked me what I think about JSLint, while the whole post is the reason I did not even start arguments or questions after Douglas speech, and the reason I will never do it.
We all have our style, Douglas has his own one, and I am happy for him he is that consistent.
Should I be a Douglas Crockford clone on daily basis? Hell no, since as I have said: I know WTF I am writing and why

Wednesday, May 25, 2011

JavaScript Builder from Falsy Values

Update: uglify-js as third option


Thanks to @kitgoncharov JSBuilder now includes the option to run uglify-js through Rhino ... still cross platform, a builder for any taste.




as promised during my workshop, I have created a Google Code Project with the builder used to demonstrate most advanced and common techniques to make a library, application, snippet, small and fast.

What Is JSBuilder

It's a truly simple Python module based over a certain hierarchy able to combine multiple files and produce a minified version of the application.
A similar approach has been used since ages with jQuery, and I am pretty sure there are tons of builders out there able to do similar task.
I personally created ages ago a similar project compatible with all windows platform.
However, that project was missing the possibility to put everything together, preserve some piece of code if necessary, replace some string runtime, and produce if necessary different outputs through the simplified module approach.
Here a build.py file example, the same you can find in the repository.

# JSBuilder example

# project name (from the root folder)
copyright = '(C) WebReflection JSBuilder from Falsy Values'
max_js = 'build/max.js'
min_js = 'build/min.js'

# file list (from the root/src folder)
files = [
"intro.js", #beginning of the closure
"variables.js", #local scope variables
"main.js", #some application logic
"functions.js", #functions declaration
"debug.js", #something useful or evil to debug
"outro.js" #end of the closure
]

# execute the task
import JSBuilder
JSBuilder.compile(
copyright,
max_js,
min_js,
files,
# optional list of serches
[ #mustaches in comments, hell yeah!
'/*{namespace}*/'
],
# with relative optional list of replaces
[
'var ' #produce var MyLib = ...

# it could be 'this.'
# this.MyLib = ...

# it could be 'my.personal.stuff.'
# my.personal.stuff.MyLib = ...
]
)

# let me read the result ...
import time
time.sleep(2)


Why Python

First of all the version is the 2.6 or higher but not compatible (yet) with version 3+.
Python to me is a sort of server side lingua-franca and it is missing by default only on Windows platform.
I would say the same about Java, with the slightly difference that in Python we don't need to create a class to perform a simple task as the one performed by JSBuilder.
If Python is not present in our system, we can easily find the installer in the python.org website while the build.py example code should be easy to understand even for non programmers.

Java As Well

Both YUICompressor and Google Closure Compiler come with a jar package which is a classic build out of one or more Java files. JSBuilder uses Java as well in order to call one compiler or another one with proper arguments and in a cross platform way so ... just in case you do not have Java installed, here the link to download what we need.

The Current Folder Structure

projectFolder
build
builder
src
Above structure is exactly the same you can find in the repository but don't worry, as you can spot in the build.py file we are free to change destination folders or paths without problems.
JSBuilder assumes in any case relative paths from the root of the application but if you really need a different structure feel free to replace the string '../' with the one you prefer ... it is an easily replaceable part of the script, just find and replace and that's it.

Multiple Projects

The build.py file is just an example but obviously we can create as many examples as we want, even inside the build.py file itself, changing just the part to replace, destination files, and/or copyright if necessary.
JSBuilder should be suitable for all sort of cases ... at least for all cases I have been facing since I have started with JavaScript (10 years of cases, I hope it's enough)

The Concept Behind

As you can see there are different sources behind the scene and the application is distributed across multiple files.
While this concept may be not that familiar or weird, this has been used by jQuery library since ever and even if teams may think it's not easy to maintain such distributed code, a proper structure following some standard could be more than we need to make everything simple.
As example, the file called variables.js contains all local scope variables reused inside other files as well.
Of course if a variable has a meaning for more than a file, it makes perfect sense to put it in the precedent one, even as undefined variables, to eventually assign it later.

Closure Compiler VS YUICompressor

If you checkout the whole project and you try to build once with YUI and once with Closure Compiler, simply swapping comment on line 63 of JSBuilder.py file, you will realize these minifiers are able to produce a completely different output.
I leave you read all comments inside JSBuilder.py in order to understand what happens there exactly, and I hope you will realize there is even more than zou have imagined.

Debugging Code

Sometimes you may need a portion of code for debugging purpose, and the not minified version of the file is the only place where it should be.
When it comes to debug, we would like to be able to export outside private variables or functions, still understanding their original names rather than the minified one.
The debug.js files as example is able to modify internal variables thanks to evil eval function.
This piece of code is surrounded by this comment:

//^
... the debug/evil code ...
//$

If you are familiar with regular expressions you can spot that ^ as "start evil code" and $ as "end evil code" have semantic meaning ... and this is what will never be included in the final minified version of our app.

Give It A Try

I hope those present in my Falsy Values workshops got the advantages a build system could bring on our daily basis work but I have written as many comments as possible to let you understand what is going on, how does it work, and why this simple script is freaking cool and it could potentially become our favorite build system.

What's Next

In my personal projects I have included an extra line at the end of the build.py able to create, per each build, documentation.
This kinda helps me to do not forget I have to document new or modified stuff, plus it gives me extra hints if some documentation has been lazily copied and pasted rather than being rewritten ... well, I honestly don't really like jsDocToolkit since JavaScript syntax has nothing to do with Java one but I agree is, at least, a tool flexible enough and still widely adopted and/or extended so ... if you all agree, I will put the magic documentation part there inside a build-with-doc.py file example.

Tuesday, May 24, 2011

setTimeout and setInterval with extra arguments ... once again!

Funny discussion today on twitter about "why on Earth IE still does not support extra arguments with setTimeout and setInterval" ... oh, well ...

The execScript Behaviour

Somebody in IE team thinks that the rest of the world should avoid extra arguments because of a bloody edge case as the third argument in IE is:

// ... seriously ...
setTimeout("Msgbox('WTF')", 0, "VBScript");


What IE Users Could Do

Well, rather than create a closure every bloody time we would like to reuse a function with different arguments, something posible 10 years ago via ActionScript 1, every web developer (and not only) misses the opportunity to avoid closures using a de-facto standard for some unknown reason not part yet of ECMAScript specifications.
For those interested I will show an example later, right now let's think about a solution compatible with VBScript for those mental developers, as I have been, brave enough to still use this language for some purpose.

setTimeout(function () {
// a closure for *this* edge case only
// rather than all cases "trapped" because of this!
execScript("Msgbox('WTF')", "VBScript");
}, 0);


Exactly The Same Behaviour!

Yes, if we use a string for setTimeout or setInterval this will be executed on the global scope, regardless where we defined this timer.
Accordingly, the latter example via execScript does exactly the same, since execScript executes synchronously on the global scope, and once trapped behind a timer, nothing change, same result .... happy? No, you are not!

The Classic Closure

The most common situation where we have problems is when we have a portable function defined somewhere else and we would like to use this function passing certain arguments there.

// somewhere else in the scope
function doStuff(obj) {
obj.stuffDone = true;
}


// later in our super cool application
setTimeout(
// the infamous closure
function () {
doStuff(myObj);
},
1000
);

The worst case scenario is where we would like to define timers inside a loop and unfortunately this is a truly common pattern that causes me repeated WTF tilt in my mind:

for (var i = 0; i < 10; i++) {
setTimeout(
// the double infamous closure pattern
(function(obj){
// the infamous closure
return function () {
doStuff(obj);
};
}(collection[i])),
1000
);
}


Closures And Scope Lookup Costs

Every time we access an outer scope variables we do a lookup in the ... well, outer scope. Every time we create a closure we pass through a function expression activation plus we create a nested scope that has to perform a scope lookup to access the outer function/variable.
Whenever this description makes sense or not, here the test you can try with not so powerful devices or mobile phones and tablet.
In my Atom N270 netbook that test is quite explicit: 50% less performances for each nested closure and its inline invoke.

Speed UP!!!

I have already described this pattern but I keep seeing too few developers adopting it.

for (var
createdOnce = function (obj) {
return function () {
doStuff(obj);
};
},
i = 0; i < 10; i++
) {
setTimeout(createdOnce(collection[i]), 1000);
}

Above example creates 11 functions rather than 20, which means we allocate and garbage collect loop + 1 functions rather than loop * 2.

Speed UP MORE!!!

The best part is that every browser I have tested but IE supports one or more argument with both setTimeout and setInterval.

for (var i = 0; i < 10; i++) {
setTimeout(doStuff, 1000, collection[i]);
}

How many extra/redundant/superflous closures and inline invoke we have created? 0.

How Difficult It Is

.. not at all.
It's pretty straight forward and it costs nothing for IE considering that you never bothered with this problem and you reached this point rather than skip this whole post at the beginning ... well, thanks for your attention :D , and this is your solution:

setTimeout(function (one) {
// only if not supported ...
if (!one) {
var
slice = [].slice,
// trap original versions
Timeout = setTimeout,
Interval = setInterval,
// create a delegate
delegate = function (callback, $arguments) {
$arguments = slice.call($arguments, 2);
return function () {
callback.apply(null, $arguments);
};
}
;
// redefine original versions
setTimeout = function (callback, delay) {
return Timeout(delegate(callback, arguments), delay);
};
setInterval = function (callback, delay) {
return Interval(delegate(callback, arguments), delay);
};
}
}, 0, 1);


Not Obtrusive

If we use above script at the very beginning of our web page there are extremely rare chances that the next script won't be able to use already the fixed version of setInterval and setTimeout for IE only.
If another script includes the same logic nothing will be redefined for the simple reason that variable one will be there so no double reassignment will be performed.
In the very safe scenario, considering we are inside our bigger outer scope created for our library, we can define those references as internal:

(function(){
// the beginning of our lib
var
setTimeout = window.setTimeout,
setInterval = window.setInterval
;


// the runtime check showed before ..

// .. the rest of the lib

// the end of our lib
}());

We may eventually decide to use some "isIE" check via conditional comments on our pages, since the solution costs nothing once minified, and have a normalized de-facto, fast, easier, behavior for every other browser.
Here the inline synchronous re-assignment for latter case:

(function (slice, Timeout, Interval) {
function delegate(callback, $arguments) {
$arguments = slice.call($arguments, 2);
return function () {
callback.apply(null, $arguments);
};
}
setTimeout = function (callback, delay) {
return Timeout(delegate(callback, arguments), delay);
};
setInterval = function (callback, delay) {
return Interval(delegate(callback, arguments), delay);
};
}([].slice, setTimeout, setInterval));


Update ... and As Summary

Of course the lookup is much faster than function creation, and this is the dedicated test but this post is about the summary of lookup and the classic closure creation historically used only because of this IE inconsistency.
Less lookup plus less closures around are faster, and numbers are there ( meaningful with slower devices )

Sunday, May 22, 2011

size maniacs or just twitterable examples ?

maybe both, but I like the idea!
Many times I have added something like #tweetcode at the end of a tweet created with the single goal to be small enough for ... well, a tweet!
@jedschmidt bought a spanish domain called 140byt.es based over github forks in order to provide all sort of tweets that may solve a specific problem in an efficient way: it kinda work on copy and paste!
Kinda ... because rules may not truly work stand alone and snippets are suggested without a "tooltip" example, at least in the main page.

What Can We Do In 140 Bytes ?

  • tweet a solution for a simple task
  • provide an idea about how to solve a task
  • solve a task in a truly efficient way
Yeah, some snippet is absolutely everything we may need to solve a problem.
The most simple example is the hex2rgb and rgb2hex, a problem that could be solved easily via bitwise operators and a tiny bit of math.

How Can 140 Bytes Be Enough ?

Using few tricks suggested in this page we can realize it is possible to shrink the code that badly to obtain a decent copy and paste tweet.

How Can We Contribute ?

Fork it and push it with some example. I have done the mistake posting a "117 bytes to bind" that follows jed logic but it is not forked yet.

function(a,b,c){b=[].slice.call(arguments,1);c=this;return function(){return a.apply(c,b.concat.apply(b,arguments))}}

Well, I'll do better next time while you can have fun and check examples right now ;)


Update
DAMN IT! Jed shrinked another byte!
function(a,b,c){b=[c=this].slice.call(arguments,1);return function(){return a.apply(c,b.concat.apply(b,arguments))}}

Monday, April 18, 2011

Native HTML5, the new IE6, and bla bla bla ...

I don't know about you guys, but I am kinda bored by all these news and tweets against Microsoft ... don't get me wrong please, you may have realized over these years I have rarely been that nice with M$ products, but there is time to complain, and time time to move forward and appreciate, at least, what we have now compared with what it was 10 years ago.

IE6 is Death, Long Life to IE6

Back in time, IE6 was the kick ass browser every web developer was dreaming about:
  • tons of security issues to hack in order to have access to any sort of private data (btw ... it's still like that ...)
  • hybrid JScript/VBScript engines with different privileges for each language and none of them based concretely over a standard
  • the predecessor of what we call today Ajax
  • hybrid box model able to understand the worst markup we can possibly imagine so ... wannabe developer friendly (I'll be back to this point later)
... and so on ... with all its glory ...

Why NO future IE will be the next IE6

Now, over last 10 years many things happened:
  • Firebird changed its name: Long life to Firefox
  • Webkit made its path down to any sort of device
  • Chrome became the must have browser
  • Opera reached version 11.50-beta-HW-accelerated-maybe
  • we are not alone anymore ... !
We are not living anymore in that era where WEB was letting us think about spiderman, internet was working only inside intranets, and no competitors were showing off yet.
We live in a different segment of the browsers timeline, a space where web surfers are more concious, less passive, and specially less ignorant ... we live in a time-frame where internet is almost everywhere and it's even portable in our pockets ... is IE there? We never cared about it, and this is the future!

Feel Free To Choose!

The Antitrust somehow forced Windows OS to let the user chose one out of 3 browsers ... I mean, more than this I wonder what do we expect ...
I have never seen such technique in any other Operating System ... but we still complain whatever IE will block people forever ...
Moreover, even if there is no choice, nobody in my family is using Internet Explorer, unless it's at work and hopefully to use work related services, not to go on Facebook or the HTML5 version of Youtube ... you know what I mean ...

Legacy Support: The Beginning Of The End

The most common excuse we can ear from a Company about the usage of IE6 is this notorious "legacy code" buzz word. For all those non techy people out there, when you ear this word this is the translation: "We don't have money to update our slow and deprecated infrastructure and we don't have enough competent people able to migrate data and business logic into something better that could bring only more value to our infrastructure and our daily basis work. Since as I have said at the beginning we don't have money, we cannot temporarily hire external Companies that would be able to do that as well ... uh, I forgot to mention we are simply out of the market 'cause we are stuck in year 2000 or earlier and new technologies ... which new technologies?".
Moreover, if we want to be reached with our online services by these companies and their employees, it is not just about the browser!
All PCs in these companies are most likely relict unable to perform any good with latest "special FXs" we all would like to put in our web ( transitions, shadows, WebGL, etc ... )

In an Ideal Web World

This is how the web development would have been in the ideal world every developer is dreaming about:
  • write once run everywhere exists
  • jQuery would have never been created
  • hobbyist and wannabe web developers, the specie more than ever growing these days mainly thanks to precedent point, would be the only web developer category so ... engineers, go and get a real job!
  • browsers won't have a name since they all act the same and there is no difference except some performances number
I am kinda joking but let's face reality. "Web For Everybody" does not mean that all browsers will be the same, it means that we must be good enough to be able to bring the web in as many browsers as possible ... this is our job, and if everything would be the same, our job would be the most boring ever ... isn't it?
The reason me and many other thousands like me are challenged on daily basis are indeed limits we keep facing in different environments.
These limits may be extremely hard to solve, cross platform speaking, but thanks to latest technologies, thanks to latest browsers, and thanks to our hard work, we can already bring what we really want in every platform: this is our job!

IE9, IE10, and the Native HTML5

I honestly do not mind about marketing words, neither users mind that much. They eventually update their browsers and if no happy, they change it again: easy.
What I do mind is that IE9 supports for HTML5 is good enough to bring fresh new content and design in every house.
What we can show today in this browser and others is unbelievable if we think we had to deal with bloody PNG alpha channel and IE6 for ages!
Why do we complain that much then?
I do believe the only day we should really complain is the day we have used all possible techniques, fallbacks, and alchemies we could imagine to shrink 100% of IE9 potentials, the same we have done over these years with IE6 ... isn't it?

Premature Complaining VS Research

The main reason people adopted libraries such jQuery is the ability to bring "unthinkable" features even in older browsers. Hacks for rounded corners, DOMContentLoaded, canvas shims, Flash fallbacks, Sockets, PNG32 support, and many others have been all over the place in latest years ... and what do we do now?
Rather than appreciate the fact we don't need them anymore and focus on what we really need next we would like to cuddle ourself behind the excuse "as usual, IE lacks behind".
Now, honestly, ask yourself how many times you have been dealing with WebSockets, Database API, WebWorkers, WebGL, and all newest technologies we may already complain about without having a clue what the hell are these useful for ... and without considering that we will always have a way to fallback.

Is WebGL missing? Not Really, Not Now

Is not that since the browser has it, everybody can use it ... is much more. WebGL opens doors to the GPU and I bet +80% of web developers out there have zero knowledge about OpenGL ES 2.0 potentials and GLES shaders language.
Apple clearly confirmed they have no intention to put WebGL support in their devices, and the reason is kinda logic: it is easy to put the GPU in an infinite loop and drain the battery or make the device unstable.
Microsoft had different reasons to do not invest much into WebGL: DirectX
Chromium invested time to create Angle which aim is to convert OpenGL ES 2.0 calls into DirectX and make WebGL possible in Windows OS as well.

Different Fallbacks

If we really care about WebGL, if we really need to put such heavy content in our web pages or our advertisements ( shaders + textures + runtime parse/translate/compile ) we can always fallback into shims through Silverlight or Flash Player, as soon as it will implement Adobe effort to bring hardware accelerated 3D content within.

Wasn't Flash Death? ... NO!

... and thanks gosh will hopefully never die! Flash has been our best friend for all those missing features now partially re-implemented in HTML5 and Flash has been always one step forward.
All those shims about storages, databases, files uploads, canvas, sockets and all the magic behind some library scene ... flash is not good but it's not that evil as well.

So, What's Next?

If it's about IE9 limits, we can simply wait that day we have discovered all possible ways to do what we need to do while if it's about WebGL we need some kick ass 3D developer with excellent knowledge of these 3D APIs: Silverlight and Molehill, aka Flash Player Incubator.
With these kind of developers out there we could have possible shims for WebGL or, even better, a jQuery3D library able to make WebGL development easier and, hopefully, without GPU loops and memory exhaustive problems.
Finally, what I really would like to see out there, is less "oh my god we are stuck forever again" and more "hey, I have spot this limit, let's figure out how to break it".

My 2 cents and happy holidays everybody, I'll be back in few days.

Saturday, April 09, 2011

ES5 NOW! ... or better, @falsyvalues

Update more than a person asked me more details and here I am: The workshop will be Thursday 19th of May on Track 3 and from 9am to 5pm. Registrations open at 8am and to be sure everything I have written is correct, please double check the schedule.

This time is not about my uncle, this time is about my workshop in Warsaw, during Falsy Values Event, and this is its description:

Massive rumours behind buzz words such HTML5 and ES5, the latest updated specification about JavaScript programming language, have surely increased confusion about where is JavaScript today, and how this language should be in the future.

Unfortunately, we all know that many users are still trapped behind really outdated browsers and their relative JS engines.

This could lead us to be stuck with old coding patterns and style but here I am to show most recent performances oriented techniques that could make the transition to this new specification less painful and efficient

  • Size matters: code size oriented techniques and advantages of a proper build process

  • Why Array extras, Object creation, and other new ES5 entries are not scary

  • Mobile and performance oriented applications: DO and DONTs

  • JS Harmony purpose and the future of JavaScript


The "It's Scripting" Logic

Too many times we convince ourself that if it is about a scripting programming language, performances are not important. Unfortunately, or fortunately, I have already said we don't have choices when it comes to "web browser environment".
It's not that if we need speed, we change programming language, this is not an option for us ... we want be fast, as fast as possible!
Everybody knows already that, even in JavaScript, a proper algorithm can be faster than a bad one written in C or ASM.
This rule could be readapted more generically considering a better pattern faster than a worse one.


ES5 Oriented Patterns

Specially on mobile and tablet, recently on desktops as well, the latest version of JavaScript could bring many advantages in therms of performances but this is not it: ES5 brings different and new approaches that we should better consider now rather than wait that all browsers "will be there" and we'll see during this workshop different examples of graceful degradation.


Performances Speaking

Not all of us are that lucky to use JavaScript on the server side only.
Even in this case, we will most likely deal with http connections and we'll have to serve some content, possibly with JavaScript as well if it's not a RESTFull service only.
Performances on web have many faces: from download size to lazy loading advantage, up to browser specific builds and the best way to serve them. All these topics will be discussed during the workshop but hey ... if I have to be honest, there are many others there that could stimulate your interest ... I am just saying :P

See you in Warsaw ;)

Saturday, April 02, 2011

See You There HTML5

My uncle Paolo opened an Italian Restaurant in London, New Barnet, and I have been there few weeks ago to visit him and bring him my congratulations.
While this is absolutely not technical, the story I would like to tell you is ...



The Real Beauty Of The Web

HTML5 is probably the most overrated buzz word since the Web started existing, most likely even more misunderstood than Ajax therm itself.
Microsoft promoted his latest IE9 (and please use it if you like IE) behind the sentence Beauty Of The Web ... well, accordingly with Microsoft the web has always been beauty since Chrome, WebKit, Opera, and Firefox became real competitors ... but this is another story.
What many did not get about this HTML5, is that it's born backward compatible, which means that as document declaration it can be used right now and there is nothing to wait for...
The real value of HTML5 is the ability to bring newer techniques where available, still being compatible in W3C therms with all those old browsers that never followed strictly Web standards.
This is beautiful, not because I have been able to create the latest "kick ass website with fantastic special effects", simply because following few steps and remembering few rules, the landing page I have created for Paolo should work in almost every damn browser with relevant market share presence.

See You There ... For Sure!

we'll know the mobile web is "ready" when links to the desktop version are understood to be unnecessary
This sentence from @grigs perfectly summarize my idea of a landing page.
While I was trying to take some inspiration, in this case checking other restaurant websites, I have realized that most of them where:
  1. absolutely unusable from mobile devices and/or tablets
  2. extremely heavy to download
  3. entirely based on Flash Player
  4. massive portals ... I mean ... seriously, it's a restaurant, not a social network!


Compromised Usability: Less Customers!

I have been living in London for a couple of years and I think I know something about the classic Londoner life style. First of all for a London citizen is quite common to have an unlimited bandwidth contract for a smart phone and about 20 pounds per month, smart phone included. Secondly, London has quite frenetic life-style and the "show me what I am looking for: NOW!" moment is specially frequent during lunch breaks and surely a nice to have in all other cases.
If we land in a page that takes ages to be downloaded and does not give us instantly info we are looking for, in a restaurant case I guess a "where and what", we have to search again. Moreover, if the page uses all cool libraries and frameworks that have never been developed for mobile and all links and sections works only through these magic libraries, the user may be totally unable to access what he is loooking for: a place to eat!

Size Matters: The Annoyed Potential Customer

Many devices show on top how much data has been downloaded so far. If we see a progress bar that takes ages to be filled and a page that is empty for more than 5 seconds after the round-trip is completed, we start thinking the page is too heavy, the device is slow or, even worst, "FFS I am paying this bandwidth!".
It's true, the web could be scary for all those people that have a pay per surf contract and if these people are scared to surf the net it's only our fault. Moreover, if the page takes too long to be visualized we go back and we re-fine the search or we click the next result in the list, isn't it?

Flash Player and the Skip Intro Anti Business

The (in)famous player we all know, the one that still shows videos on Youtube, has been wrongly used since the beginning when it comes to Web content. The classic skip intro for a 500Kb of bullshit nobody is interested about is the biggest epic fail of the history of web. Put a link in the main page that points to the intro? That would have been too much user friendly so ... naaaaaaaa!
Even worst, many devices do not support the Flash Player since only lately this has become suitable for mobile devices without draining the little battery.
If your business entry point cannot be reach by all possible customers, you paid the "skip intro" to ruin the potential of your business since all Apple products, as example, won't be able to reach your business.

The Restaurant Community Epic Fail

When I have seen that Paolo created a facebook group, the first thought has been: well done uncle, keep it updated!.
When Paolo asked why the site I was planning to create could not have the community section, this is what I have answered:
  • it's a restaurant, not a social network
  • nobody comes back to a restaurant website. Once they reach the place, they'll come back to the restaurant, if happy, or they won't
  • if anybody is interested in your group, there is a link that points to this group ... and since facebook is the only place they will go back for sure, on-line speaking, let them chose to join the group and be notified via their home screen wall
Paolo understood my points, I still do not get why on earth a restaurant should create a community online with events notification, the registration form etc etc ... seriously, let social networks do this job and don't waste your time/money for this stuff ( KISS and YAGNI )

As Summary

I made this page as simple "best luck, uncle Paolo" present and over a week end and I hope you will like it. It is simple, it follows my favourite principles, and it's not pretentious as many other restaurant websites I have seen out there.
Why did I post about it? To make a bit of advertisement for my uncle delicious food from Tuscany, and to tell the story about how the web is still too much stereotyped and rarely ad-hoc from real business value perspective.
Keep it simple, and try to obtain the most important goal first: everything else could be added later, and only if you need it!

Tuesday, March 29, 2011

Rewind: getters & setters for all IE with cross browser VBClass!

spoiler: if once again everybody knew except me, you guys should do something to be better indexed in Google ... while if this is totally new and cool, well, you are welcome :)



Sometimes I am stubborn, so stubborn, that even if it was me writing this post, and this one after, I have never given up about IE < 9 getters and setters ... "there must be a way", I have thought during last days, and ... yes, eventually I have found the way!

Test Driven Developed Solution

I have decided the possible behaviour, I have implemented all use cases, and I have successfully validated them against all browsers I could came up, with the exception of a single test, the first one, which fails in those browsers unable to freeze an object ... well, these browsers are disappearing thanks to their suggested, or automatic, updates, so everything is fine.
Here the unit test that should cover 100% of the used JavaScript and/or the used VBScript where available (only IE < 9 so please don't freak out yet!)

The Horrendous VBScript for IE

This wannabe Web programming language has been there, and hated, for ages ... but actually, if we learn all its gotchas we may end up thinking it is not that bad!
The main problem is to learn this "whatever it is language" and trust me: you don't wanna do that in this HTML5 era ... do you ?!

Not Only Get & Let, There Is A "Set" As Well!

Where good old dojo experimental Observable stopped, I didn't.
I kept investigating what the hack was going on behind the scene, forcing my fabulous IE9 to digest such Jurassic web programming language as VBScript is.
What I have discovered yesterday evening, is that when we set a property to a VBScript "unknown" object the Let definition is invoked only with primitives, where primitives are all those JavaScript variables which typeof is not equal to "object", with the exception of null value, and "function".
Once discovered this, the door to a proper implementation able to behave the same in all browsers became easy, and this is why I have introduced a new Class definition, the VBClass

What The Hell Is VBClass

VBClass is a global function able to create global factories, and these are the rules for a VBClass definition object:

  1. the definition of a VBClass IS static, which means once we have defined the structure of our instances, we cannot add, delete, or change arbitrary the number of properties

  2. since VBScript does not accept properties that start with an underscore, the convention to define a property "protected" must be different, as example using the underscore at the end as Closure Library does for whatever reason

  3. if a definition property is a function, this will be considered an immutable method of each instance created via this factory

  4. if a definition property has a value, its reference can be changed at any time and with any kind of object, function included, but in latter case it will not be possible to attach method runtime, but it will surely be possible to invoke the function property via call or apply, specifying the current object



A Full Specs VBClass Example


VBClass("FullSpecs", {
constructor: {
value: function (arg) {
// calls the method
this.method(arg);
}
},
method: {
value: function (arg) {
// invokes the setter
this.getSet = arg;
}
},
getSet: {
get: function () {
// returns the "protected"
return this.getSet_;
},
set: function (value) {
// assign the "protected"
this.getSet_ = value;
}
},
getSet_: {
// default "protected" value
value: null
}
});

var
genericObject = {},
test = new FullSpecs(genericObject)
;

test.getSet === genericObject; // true!


Pros And Cons Of VBClass

These are a few of pros about the precedent described VBClass limits/behavior:

  1. we have to think more about what we really need in our class, forgetting the completely dynamic JavaScript behaviour

  2. we are forced to follow a better convention for what we would like to define "protected properties"

  3. we can trust our defined methods, and we have to stick with them. This is a good/common approach if we consider a constructor.prototype runtime change a bad practice

  4. properties are properties, so there is nothing ambiguous about what is a method and what is a property: only the method can be invoked directly through the instance/variable/object, everything else is a property and there is no magic context injection there, neither for set functions


However, there are few cons to consider about this technique: unified behaviour through hosted VBScript objects means slower performances!
This means that VBClass created classes cannot be used for everything and there must be a valid reason to choose them in favour of normal JavaScript functions and their prototype nature.
A good reason could be, as example, the creation of those public object that would like to implement the coolness of a robust, cross platform, getters and setters implementation ... but be careful! If these objects are created hundred times during our application life-cycle, the performance impact could be massive and specially for older IE browsers.
Fortunately, with mobile browsers, IE 6/7 for Windows Phone 7 a part that I have not tested yet, the ideal scenario should fallback into the Object.create implementation, the one used in the main file, the only one needed, hopefully, as soon as users will update their browsers.

How To Use VBClass

Grab the source code or the minified version from my Google Code VBClass Project. Once all VBClass files are in the same folder, you can simply include the VBClass.loader.js on the top of your page and the rest of the magic is done.

<script
type="text/javascript"
src="http://vbclass.googlecode.com/svn/trunk/min/VBClass.loader.js"
></script>

Please copy VBClass locally to avoid round-trip and obtain better performances (also the trunk version in Google Code is not gzipped).

Have fun with VBClass ;)

Wednesday, March 16, 2011

Object.defineHybridProperty

Update Yes, I did it: getters and setters for IE < 9 and other browsers


After my early Hooorrayyyy! about compatible IE < 9 getters and setters, I have been experimenting a bit more on how to solve the JSObject to VBVariant and vice-versa assignment and the result was an horrendous monster loads of potential memory leaks and performances implications for the already slow bounce of browsers such IE8, 7, and 6.
Since limitations were also too many, as described in this even earlier attempt from dojo framework, I have realized that VBScript was simply a no-go, or better, probably the wrong answer to the question: how can I have cross-browser getters and setters?

The jQuery Hybrid Answer

Back in 2009, James Padolsey described the jQuery framework as a sort of getters/setters simulator API, comparing the semantic and beauty of non-standard Spidermonkey __defineGetter__ and __defineSetter__, against jQuery coding style, where many "methods" could be considered as getters or setters.

// get the innerHTML of the first node found through the selector
$("#selector").html();

// set the innerHTML of the first(?) node found through the selector
$("#selector").html("
");

As showed above, the jQuery().html method can be considered a friendly answer for a cross browser get/set implementation, and surely much more friendly than what antimatter15 proposed some time ago (Pssss! dude, I could not find your real name in the "About" section ...).

My "due jQuery success, why not!" Proposal

In ES5 everything is so natural and simple, Object.defineProperty and Object.defineProperties work like a charm and IE9 with all other browsers as well. We may decide to use good old __defineGetter/Setter__ as fallback for older Opera, Chrome, Safari, or Firefox, but not for IE since these methods are not supported at all.
However, even using these fallbacks, the descriptor object will result inconsistent because writable, enumerable, and configurable properties won't act as expected.
At this point I have decided to fallback into a "jQuery approach" solution that will behave exactly the same in all old and newer browsers, being still able to use an ES5 like descriptor that in a not that far away future won't even need to be changed at all, it will simply work.

A generic Person.prototype Descriptor



var personDescriptor = {
// requires council notification on change
name: {
get: function () {
return this._name;
},
set: function (name) {
// notify here the council about this change
this._name = name;
}
},
// this property is unfortunately immutable (via public access)
age: {
get: function () {
return this._age;
}
},
// simply a method that occurs once per year
birthday: {
value: function () {
this._age++;
}
}
};


Current ES5 Person "Class" Example



//* ES5 example
function Person(name, age) {
// a new Person in town
this._age = age || 0; // default, just born
this.name = name;
}

Object.defineProperties(Person.prototype, personDescriptor);

var me = new Person("Andrea", 32);
// will throw an error
// me.age = 20;
alert([me.name, me.age]); // Andrea, 32
me.birthday();
alert(me.age); // 33
//*/


Current ES3 Person "Class" Example



//* ES3 example
Person = function Person(name, age) {

// a new Person in town
this._age = age || 0; // default, just born

// we still want to notify the council,
// no direct this._name set
this.name(name);

}

Object.defineHybridProperties(Person.prototype, personDescriptor);

var me = new Person("Andrea", 32);
// nothing will happen
// me.age(20);
alert([me.name(), me.age()]); // Andrea, 32
me.birthday();
alert(me.age()); // 33

// wanna know what they are?
alert(me.name);
alert(me.age);
alert(me.birthday);
//*/

The source code of Object.defineHybridProperty, together with Object.defineHybridProperties, is here and as you can see it's a quite simple and compact piece of code.

Use Cases and DONTS

The function name should be explicit enough, and it's used to define hybrid properties.
Hybrid properties could be confused with methods ... and actually, all hybrid properties that have a get and/or set descriptor, become de-facto an object methods with current constrain: zero arguments to get, 1 single argument to set.
Use cases have been already described, a jQuery like API could use without problems the current approach, making the future ES5 only refactory less painful than whatever other get/set approach.
Indeed, once we know which descriptor is using getters/setters, all we have to do is to remember which property has been made hybrid, and change accordingly each invoke with arguments as assignment, and removing brackets from every other empty invoke.
Please Note I will update later the code in order to properly assign Object.prototype native names such toString so that IE browsers will consider them as well.
Done, it's updated and 409 bytes minified and gzipped, have fun :)

Wednesday, February 23, 2011

...btw, getters & setters for IE 6, 7, and 8 (almost!) : Object.createStatic

Update Yes, I did it: getters and setters for IE < 9 and other browsers


Update apparently Dojo framework explored this stuff before me



Re-Update: More limitations!!!


Apparently I have said "Hooray!" too early, @_bga told me that this way is compatible with primitives only since the moment we have a property with an object or a function, this will converted into string.
So: don't return objects or functions since these will not work as expected!
Well, still something tho ... I should probably change the title with a big "almost" ...



... pretty much, the "dream comes true" features that could open hundreds of doors for current Web development status is here, but before we can understand properly the example page, we surely need a bit of introduction about the topic ...

Getters/Setters For Everybody!

Getters and Setters are beautiful, powerful, and the ideal scenario for whatever developer behind any sort of API.
Getters and Setters work perfectly in all browsers but old IE, where the version is almost 8, due possibility to use Object.defineProperty at least with DOM prototypes and some hosted object, and it goes down to all versions we know: 7, 6, ... etc

How Does It Work

"Proxying" VBScript via JScript global execScript method, it is possible to create a VBScript Class that via factory pattern assigns a private JS object into VBScript instance, passing through a runtime create JavaScript function that will act as a factory to return the private scope object passed to create the relationship ...



IE Getters and Setters

I had the same expression when I have read something like this, but I have been too lazy to even think about a better solution.
I kinda regret I have abbandoned my VBScript experiments at some point but ... you know, I am mainly dealing with mobile browsers where IE, as exclamation, meaningful word, or acronym, is basically never mentioned.

Rewind, We've Got Getters and Setters in IE!!!

At least we have the possibility to create a static object, where "static" means that we cannot set runtime properties the way we use to with whatever JavaScript object.
In few words, and at least for me for the first time, we have to deal with properly defined Classes inside a prototypal inheritance based programming language, and one of the most highly dynamic I know.

Object.createStatic

I have tried hard to respect as much as possible new ES5 Object.defineProperties definition object, but it was not possible, for cross-browser consistencies problem, to preserve the first argument as te one that suppose to be extended via definition object, so here's the signature:

Object.defineStatic(
definitionObject:JSObject
):StaticObject;

And here the same example in JS code:

var Static = Object.createStatic({
// public
value: {
get: function () {
return this._value;
},
set: function (value) {
this._value = value;
}
},
// "protected"
_value: {
writable: true,
value: 123
}
});

// will invoke the setter
Static.value = 456;
alert(Static.value); // 456

// will throw an exception
// or it won't work
Static.whatever = "no way";


Not Suitable For Prototype

Unfortunately, if we want to preserve a cross browser behavior, we should consider that the "Static" object cannot be used as a prototype definition, due its "hosted" nature, which comes from a VBScript Class, and for this reason cannot be handled as every other object.

Suitable For ...

We can use this hack to create those kind of object that would like to be:

  • secure, it is really challenging, almost impossible in IE, to redefine a property that has been defined already via definition object

  • reasonable amount, being each Singleton creation truly expensive for the already slowest browser still on the market, aka IE < 9, we cannot benefit from this approach in order to create hundreds of instances during an application lifecycle

  • any sort of API, where the main entry point is always the same object, used mainly as a namespace, and the "magic" we would like to add could have "no limits"



As Summary

This stuff has been around for almost two years, and I am the first one that never thought about it too much, or never felt so much the need to have getters and setters in IE. Now, at least from what I knew so far, you can play with future oriented code, waiting for your worst enemy to simply die thanks to the market offer.
It's your call, I am just giving a hint ;)

Once again, the source code!

Wednesday, February 16, 2011

All You Need for JSONP

I have just uploaded a truly simple, still robust, function able to do generic JSONP without pretending too much magic.

The concept is simple, we pass the url, including the parameter name used to communicate the callback name, and a callback as second argument ... that's it, 202 216 bytes minified and gzipped ( many thanks @jdalton for the catch )

Here an example:

<!-- the generic HTML page -->
<script src="JSONP.js"></script>
<script>
this.onload = function () {
var many = 0;
JSONP("test.php?callback", function (a, b, c) {
this.document.body.innerHTML += [
a, b, ++many, c
].join(" ") + "<br />";
});
JSONP("test.php?callback", function (a, b, c) {
this.document.body.innerHTML += [
a, b, ++many, c
].join(" ") + "<br />";
});
};
</script>

And here the testable demo result that should work with every bloody damned browser.

What's on the server? Nothing more than this:

<?php
if (isset($_GET['callback'])) {
header('Content-Type: application/javascript');
exit($_GET['callback'].'.call(window, "Hello", "JSONP", "!!!")');
}
?>


Enjoy ;)

Sunday, January 30, 2011

PHP 5.3.5 Update on PAMPA-J

Quick post, for one of those 7000 developers that use PAMPA, there is a new zip upgrade to download able to bring PHP 5.3.5 in your PAMPA folder.

The structure inside this zip is the same one, the service should be stopped or quitted before you can extract and replace all files.
Please backup your current php.ini file, inside PAMPA/config folder, in order to eventually update the new version or simply put it back as it was before ( really few changes there since the 5.3.0RC1 ).

The destiny of this project is still under evaluation but at least now it is offered with the latest, stable, PHP version.

Have fun ;)

Tuesday, January 25, 2011

ES6, Harmony, and JS++

... where JS++ is simply metaphoric, in the meaning of "empowered JS" :)

Here the slides I have showed last friday during another team meeting, enjoy!

Saturday, January 22, 2011

What I Will Never Get ...

... is why non technical people are often making technical decisions. And this is, my developer friend, what you may face during your path ...

An unusual topic for this tech blog, a hopefully real case scenario for all those developers out there: don't believe in the startup concept, as well as don't believe in the corporate concept too much; just feel your skills, and move forward!

Monday, December 27, 2010

ES5 Common Design Patterns Examples - Part 1


// Abstract Factory
/*
({}).createInstance()

(function (a, b, c) {
this.sum = a + b + c;
}).createInstance([1, 2, 3])

*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Object.prototype,
"createInstance",
{
value: (function (create) {
return function createInstance(args) {
var
self = this,
isFunction = typeof self == "function",
obj = create(isFunction ? self.prototype : self)
;
isFunction && args != null && self.apply(obj, args);
return obj;
};
}(Object.create))
}
);

// Abstract Builder
/*
var person = Object.builder({
setup: function (name) {
this.create();
this.instance.name = name;
}
});
person.setup("WebReflection");
alert(person.instance.name);
person.create();
person.instance.name = "Andrea";
alert(person.instance.name);
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Function.prototype,
"builder",
{
value: function (methods) {
var
$create = Object.create,
self = this,
proto = self.prototype,
obj
;
return $create(methods, {
instance: {
get: function get() {
return obj;
}
},
create: {
value: function create() {
obj = $create(proto);
self.apply(obj, arguments);
}
}
});
}
}
);

// Multiton + Singleton pattern
// (via lazy initialization)
/*
function Car(){}
var car = Car.getInstance();
alert(car === Car.getInstance());
alert(car !== Car.getInstance("bmw"));
alert(Car.getInstance("bmw") === Car.getInstance("bmw"));
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Function.prototype,
"getInstance",
{
value: function (key) {
var
create = Object.create,
instances = {},
self = this,
proto = self.prototype,
instance
;
Object.defineProperty(
self,
"getInstance",
{
value: function getInstance(key) {
return key == null ?
instance || (instance = create(proto)) :
instances.hasOwnProperty(key) ?
instances[key] :
instances[key] = create(proto)
;
}
}
);
return self.getInstance(key);
}
}
);

// Prototype
/*
var definition = {some:"thing"};
var inherited = Object.create(definition);
*/
Object.create;

// Abstract Adapter
/*
function Person() {}
Person.prototype.setName = function setName(_name) {
this._name = _name;
};

var getter = {
toString: function () {
return this._name;
}
};

var me = {};
me.adapt(Person);
me.setName("WebReflection");
me.adapt(getter);
alert(me);
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Object.prototype,
"adapt",
{
value: (function (proto) {
return proto in {} ?
function adapt(Class) {
this[proto] = typeof Class == "function" ? Class.prototype : Class;
} :
function adapt(Class) {
var self = this;
typeof Class == "function" && Class = Class.prototype;
for (proto in Class)
self.hasOwnProperty(proto) || (self[proto] = Class[proto])
;
}
;
}("__proto__"))
}
);

// Abstract Composite
/*
function AddToBody(value) {
this.value = value;
}
AddToBody.prototype.value = "";
AddToBody.prototype.exec = function () {
document.body.appendChild(
document.createElement("p")
).innerHTML = this.value;
};

var many = AddToBody.composite();
many.push(
new AddToBody("this"),
new AddToBody("is"),
new AddToBody("a"),
new AddToBody("test")
);

this.onload = function () {
many.exec();
alert(many.value);
many.value = "everybody like this";
many.exec();
alert(many.value);
};
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Function.prototype,
"composite",
{
value: (function (defineProperty) {
return function composite() {
function get(key) {
function retrieve(item) {
return item[key];
}
return function get() {
return map.call(this, retrieve);
};
}
function set(key) {
function assign(item) {
item[key] = this;
}
return function set(value) {
forEach.call(this, assign, value);
};
}
function wrap(method) {
function apply(item) {
method.apply(item, this);
}
return function wrap() {
forEach.call(this, apply, arguments);
};
}
var
composite = [],
forEach = composite.forEach,
map = composite.map,
proto = this.prototype,
key, value
;
for (key in proto) {
if (typeof(value = proto[key]) == "function") {
composite[key] = wrap(value);
} else {
defineProperty(
composite,
key,
{
get: get(key),
set: set(key)
}
);
}
}
return composite;
};
}(Object.defineProperty))
}
);

// Observer/Listener
/*
function hello(e) {
alert(e.type);
}
var obj = new Listener;
obj.addEvent("hello", hello);
obj.addEvent("hello", hello);
obj.fireEvent("hello");
obj.fireEvent({type:"hello"});
obj.removeEvent("hello", hello);
obj.fireEvent({type:"hello"});
*/
var Listener = (function () {
// (C) WebReflection - Mit Style License
function Listener() {
handler.value = {};
defineProperty(this, "_handler", handler);
}
function fire(callback) {
callback.call(this.target, this);
}
var
proto = Listener.prototype
defineProperty = Object.defineProperty,
handler = {
value: proto
},
empty = []
;
Object.defineProperties(
Listener.prototype,
{
addEvent: {
value: function addEvent(type, callback) {
var stack = this._handler[type] || (this._handler[type] = []);
stack.indexOf(callback) < 0 && stack.push(callback);
}
},
removeEvent: {
value: function removeEvent(type, callback) {
var
stack = this._handler[type] || empty,
i = stack.indexOf(callback)
;
-1 < i && stack.splice(i, 1);
}
},
fireEvent: {
value: function fireEvent(e) {
typeof e == "string" && (e = {type: e});
e.target = this;
(this._handler[e.type] || empty).forEach(fire, e);
}
}
}
);
return Listener;
}());

Sunday, December 26, 2010

100% Client Side Image Resizing

... I know, I have said "Happy Holidays" already, but yesterday, after a (annoying) picture upload in Facebook, I had a an idea ... why on earth I should have a Java plugin to perform images resizes on Facebook? Why on earth if I don't have such plugin I have to wait the possibly extremely long upload, up to 10x slower for high quality images, stressing Facebook servers for such "simple" operation as an image resize/resample could be?

The FileReader Interface

In the W3C File API, I guess part of the HTML5 buzzword, we can find all we need to perform the operation we want totally on client side. The interface is called FileReader, and it provides functionalities to read chosen files from an input node with type file, and that's it: we can even disconnect from the network and keep resizing and saving images without problems.

The Canvas Trick

Still into HTML5 buzzword world, the canvas element and it's 2dContext.drawImage method is the key to perform a resample/resize operation. It's not about changing a DOM Image node size and show it, it's about creating a totally fresh new image with exactly desired pixels size.
Once this is done, it is possible to send via Ajax the bas64 encoded image or it is possible to simply save the created image or reuse it, or resize it again ...

The Demo Page

This is the demo page I gonna show you soon, the code is hopefully self explanatory:

<!doctype html>
<html>
<head>
<title>JavaScript Image Resample :: WebReflection</title>
</head>
<body>
<input id="width" type="text" value="320" />
<input id="height" type="text" />
<input id="file" type="file" />
<br /><span id="message"></span><br />
<div id="img"></div>
</body>
<script src="resample.js"></script>
<script>
(function (global, $width, $height, $file, $message, $img) {

// (C) WebReflection Mit Style License

// simple FileReader detection
if (!global.FileReader)
// no way to do what we are trying to do ...
return $message.innerHTML = "FileReader API not supported"
;

// async callback, received the
// base 64 encoded resampled image
function resampled(data) {
$message.innerHTML = "done";
($img.lastChild || $img.appendChild(new Image)
).src = data;
}

// async callback, fired when the image
// file has been loaded
function load(e) {
$message.innerHTML = "resampling ...";
// see resample.js
Resample(
this.result,
this._width || null,
this._height || null,
resampled
);

}

// async callback, fired if the operation
// is aborted ( for whatever reason )
function abort(e) {
$message.innerHTML = "operation aborted";
}

// async callback, fired
// if an error occur (i.e. security)
function error(e) {
$message.innerHTML = "Error: " + (this.result || e);
}

// listener for the input@file onchange
$file.addEventListener("change", function change() {
var
// retrieve the width in pixel
width = parseInt($width.value, 10),
// retrieve the height in pixels
height = parseInt($height.value, 10),
// temporary variable, different purposes
file
;
// no width and height specified
// or both are NaN
if (!width && !height) {
// reset the input simply swapping it
$file.parentNode.replaceChild(
file = $file.cloneNode(false),
$file
);
// remove the listener to avoid leaks, if any
$file.removeEventListener("change", change, false);
// reassign the $file DOM pointer
// with the new input text and
// add the change listener
($file = file).addEventListener("change", change, false);
// notify user there was something wrong
$message.innerHTML = "please specify width or height";
} else if(
// there is a files property
// and this has a length greater than 0
($file.files || []).length &&
// the first file in this list
// has an image type, hopefully
// compatible with canvas and drawImage
// not strictly filtered in this example
/^image\//.test((file = $file.files[0]).type)
) {
// reading action notification
$message.innerHTML = "reading ...";
// create a new object
file = new FileReader;
// assign directly events
// as example, Chrome does not
// inherit EventTarget yet
// so addEventListener won't
// work as expected
file.onload = load;
file.onabort = abort;
file.onerror = error;
// cheap and easy place to store
// desired width and/or height
file._width = width;
file._height = height;
// time to read as base 64 encoded
// data te selected image
file.readAsDataURL($file.files[0]);
// it will notify onload when finished
// An onprogress listener could be added
// as well, not in this demo tho (I am lazy)
} else if (file) {
// if file variable has been created
// during precedent checks, there is a file
// but the type is not the expected one
// wrong file type notification
$message.innerHTML = "please chose an image";
} else {
// no file selected ... or no files at all
// there is really nothing to do here ...
$message.innerHTML = "nothing to do";
}
}, false);
}(
// the global object
this,
// all required fields ...
document.getElementById("width"),
document.getElementById("height"),
document.getElementById("file"),
document.getElementById("message"),
document.getElementById("img")
));
</script>
</html>


The resample.js File



var Resample = (function (canvas) {

// (C) WebReflection Mit Style License

// Resample function, accepts an image
// as url, base64 string, or Image/HTMLImgElement
// optional width or height, and a callback
// to invoke on operation complete
function Resample(img, width, height, onresample) {
var
// check the image type
load = typeof img == "string",
// Image pointer
i = load || img
;
// if string, a new Image is needed
if (load) {
i = new Image;
// with propers callbacks
i.onload = onload;
i.onerror = onerror;
}
// easy/cheap way to store info
i._onresample = onresample;
i._width = width;
i._height = height;
// if string, we trust the onload event
// otherwise we call onload directly
// with the image as callback context
load ? (i.src = img) : onload.call(img);
}

// just in case something goes wrong
function onerror() {
throw ("not found: " + this.src);
}

// called when the Image is ready
function onload() {
var
// minifier friendly
img = this,
// the desired width, if any
width = img._width,
// the desired height, if any
height = img._height,
// the callback
onresample = img._onresample
;
// if width and height are both specified
// the resample uses these pixels
// if width is specified but not the height
// the resample respects proportions
// accordingly with orginal size
// same is if there is a height, but no width
width == null && (width = round(img.width * height / img.height));
height == null && (height = round(img.height * width / img.width));
// remove (hopefully) stored info
delete img._onresample;
delete img._width;
delete img._height;
// when we reassign a canvas size
// this clears automatically
// the size should be exactly the same
// of the final image
// so that toDataURL ctx method
// will return the whole canvas as png
// without empty spaces or lines
canvas.width = width;
canvas.height = height;
// drawImage has different overloads
// in this case we need the following one ...
context.drawImage(
// original image
img,
// starting x point
0,
// starting y point
0,
// image width
img.width,
// image height
img.height,
// destination x point
0,
// destination y point
0,
// destination width
width,
// destination height
height
);
// retrieve the canvas content as
// base4 encoded PNG image
// and pass the result to the callback
onresample(canvas.toDataURL("image/png"));
}

var
// point one, use every time ...
context = canvas.getContext("2d"),
// local scope shortcut
round = Math.round
;

return Resample;

}(
// lucky us we don't even need to append
// and render anything on the screen
// let's keep this DOM node in RAM
// for all resizes we want
this.document.createElement("canvas"))
);


The Resample Demo In Action

First input for the width, second input for the height, if one out of 2 is defined, the resize maintain the aspect ratio.
You can even disconnect your machine from the network, since nothing is absolutely stored or saved in my website, everything simply runs in your machine.
Compatibility? Minefield and latest Chrome work pretty well. I don't have my MacMini with me right now but I will test eventually WebKit nightly later.
Happy end of 2010

Friday, December 24, 2010

Happy Holidays

I'd like to recycle this good old experiment to wish all WR readers nice holidays, if any :D



See you soon next year with new web development adventures ;)

The Status of Mobile Browsing

In this year I have done more tests than ever over all these tiny and shiny portable devices and I'd like to share with the Web community the result of my experiments at the end of this 2010. "why not before xmas, ffs?" ... because whatever you bought as present for you or your relatives, will hopefully be updated soon with latest systems and related browsers :)

The Dedicated WebKit ... Nightmare!

As ppk mentioned already in Front Trends conference, we have basically only 5 browsers in our desktop PCs/Macs/Linuxes machines. Much more fun comes when we think we are dealing with a single browser, a generic WebKit based one, and we discover that there's no browser similar to another one, every bloody device has its own implementation with few exceptions represented by Safari Mobile, almost the same in iPad, iPod, and latest iPhone.

WebKit and CSS(3)

Even if the CSS engine is basically the same for every single specific implementation, the number of supported, and so called, CSS3 features, are platform and device dependent. Something works as expected, something simply does not work, while something pretends to work but it does not until we force the rendering trying to activate Hardware Acceleration.
The classic trick to do this is to apply 3D transformation to the main container of our styled stuff:

#styled-stuff-container {
-webkit-transform: translate3d(0, 0, 0);
}

Above technique could solve many headaches when a portion, or the whole body, looks fucked up ... give it a try but please note that GPU buffer will rarely support big images and these could cause a massive performances impact.
An ideal document size for mobile browsing should not reach more than 2~3000 pixels height ... considering a reasonable width, after that we could have problems.

Tricks a part, the horrible side effect of unsupported CSS features is that features detections are not really a solution ... "eye result" detection would be the way to go but it requires a pixel per pixel check.
The "eye result" detection is something I have invented right now as CSS check automation. We should have a snapshot of the container, saved as png, a snapshot created runtime from the rendered container, impossible with current DOM API, and two canvas elements in order to compare both image data ... where to speed up the process in JS world, we could simply compare the returned base64 encoded result of both snapshots as fast char-by-char (threaded as ints) match (e.g. "a" == "a").
This is fantasy right now, and it implicates complex, bandwidth greedy, operations I would never suggest ... but I am just saying ... that we should never trust the result we have on our desktop WebKit or another device WebKit based, we should always test results in target if we would like to avoid surprises.
Finally, messed up CSS could cause indirectly so many computation behind the scene we cannot even imagine ... until we discover the the whole interaction is compromised.
As example, those pages strongly styled in an unreasonable way through tons of overwritten or inherited CSS, in a deeply nested DOM, simply are unusable!

WebKit and JavaScript(ES5)

Under the flag "we support HTML5", many things implemented in ES5 specs are already there indeed. In few words these tiny devices are already "10 years" ahead whatever destktop browser based on Internet Explorer ... which is good, which gives us the possibility to forget all crap we use to detect, filter, change, assume, until now.
This is the reason 99% of common web libraries out there are obsolete when it comes to the massive amount of features detections these libraries use to understand the exact version of IE, Firefox, or Opera ... all this stuff is crap, is bandwidth unfriendly, and unnecessary.
A good library for mobile browsing is a library dedicated for mobile browsing ... where even features detections could cost time (slower CPUs) and where most of the time these features detection, specially those for edge cases, can be dropped in favour of the good old User Agent string.
Yes, you read correctly, features detections we know could simply fail in all these variants of WebKit based browsers.
Some device could expose hosted features that are not available, some other could not expose anything but still support what we are looking for ... there are many examples that caused me nightmares during my experiments and no simple solution.
The User Agent sniff sometimes is the best, cheap, fast, solution we could possibly adopt and it will rarely fail when it comes to mobile.
Last, but not least, faster WebKit implements V8 engine, the google diamond, but others may implement the classic JavaScriptCore, with or without "Extreme" acceleration.

Native JSON Support

Almost all mobile browsers support native JSON. This is essential for fast and safe JSON strings and JS objects conversion into JSON strings.
I am counting seconds for the day Douglas Crockford JavaScript implementation of JSON will be redundant/superfluous, same as I am counting seconds until attachEvent will disappear from the Earth!

GeoLocation API

A mobile browser that does not come with GeoLocation API support is a death device. Mobile therm talks by itself, it's the user "on the way", full stop. Remove the possibility to share or know the location and good by "to go" experience.

session and local Storage Limits

Whatever freaking cool idea you come with these storages is not enough. What all these demo and examples around the net are saying is not exact. First of all the correct way to set an item is via official API, and not via direct access:

localStorage.setItem("setItem", "whatever");

// rather than
localStorage.setItem = "whatever";

// cause you don't want unexpected results later
localStorage.getItem("setItem"); // whatever

localStorage.setItem // ... what do you expect?
// a method or "whatever"

To know more about this problem, if interested, have a look.

Finally, and most important, setItem could fail once the storage reaches the memory limit which is not exposed (hopefully yet) through the API.
In few words we can have a nice Exception the moment we try to set an item, even the same, and the storage is "full".
To avoid problems, even if this is not a solution, use a bloody try catch block every time we need to set an item:

try {
localStorage.setItem("key", "bigValue");
} catch(e) {
// now we are fucked ... where do we put bigValue?
// we can still do stuff or clear some value
localStorage.clear(...)
}

The limit I am talking about is around 2Mb but it may vary.

Database API

Something nobody liked that much, something I love since the beginning. The SQLite database behind the scene is the best portable, tiny, and cross platform database engine we could possibly use on a browser. I am not a big fun of all these NoSQL fuzz, just use what the fuck you need when the fuck you need.
In this case the Web Database API provides a nice message automatically when the application tries to store more data than allowed, letting us being able to pass the limit specified at the beginning.
A good compromise is to set the initial storage value to 2 megabyte, maximum 5, and after that limit it will be the device able to allocate more space if necessary, adding other 2, up to 5, megabytes to curent database.
Rather than try catch mandatory blocks, we have callbacks for error handling but, right now, I have never been able to reproduce in a real scenario problems with the SQLite database size.

WebWorkers

These beasts could be the ideal solution in a multi-core device. Unfortunately, webworkes do not come for free with current mobile CPUs. It does not matter if these are operated behind the scene since the scene itself could interact slower than usual due tasks priorities.
Not a big deal considering webworker are not widely supported yet ... but still bear in mind the CPU is "that one", you better learn better algo or JS practices to speed up things rather than delegate piece of massive stuff to computate on the background.
A tiny temporary block is, in my opinion, much better than a persistently slow interaction due webworkers.

Touch Support

Touch events are the mandatory choice for mobile web development ... people should completely forget about mouseover and this kind of interaction bullshit, when it comes to device ... there is no fucking mouse on device, and these events should be used only as quirk fallback for those devices that do not expose properly touch events.
Touches are truly simple and everything we need for whatever interaction: touchstart, touchmove, touchend.
There will never be a touchmove without a touchstart, neither a touchend without a touchstart. Things are slightly complicated when we assume that a touchstart, followed by a touchend, won't fire a touchmove in the meanwhile.
When we start touching our smartphone screen the area we cover with our finger may vary due pressure on the screen. If a touchstart event has been fired already but the area is "enlarging" from the same finger, we won't have another touchstart, we will be notified with a touchmove.
There are concepts as "touch tolerance" that are already applied on all layers, included hardware, but this is not enough if we would like to have full control.
Finally, touch events are a classic example where features detections fails. The only way to be sure 100% that the device will work with touch events is to listen to both touchstart and mousedown and accordingly with the one fired first, usually the touch if fired, we can switch/communicate that the device is compatible. All our detections may fail accordingly with the device or the implemented WebKit version.

The Click Event

In some device, as is for example the delicious Palm Pre 2 I am testing these days (thanks again Palm!) there are no touches, even if the browser exposes them, so it is not possible to drag or scroll via JavaScript but it is possible to trust the classic click event.
The click is indeed the only universal fallback we can use to simulate interactions. Both new and old devices, included most recent Windows Mobile with that brEwser, will always react on click events. Pal Pre 2 does not expose right functionality for quirks mousemove neither ... and I am talking about web pages, if we create our own Application through Mojo framework ... well, things changes (again).

The Canvas Element

Almost every mobile browser supports canvas. Unfortunately, the Hardware Accelerated Canvas is still a myth. Canvas will be HW Accelerated hopefully soon, but what I have spotted right now, is that as example iOS 4.0.2 or lower has a tremendously faster canvas manipulation than iOS 4.2, or the latest iOS you can install in your iPad or iPhone. I am really sorry if you have already screwed up your mobile browsing experience updating this OS with latest ... since we all know you cannot go back now, let's hope Apple QA will test properly, next update, canvas performances ... epic fail from my point of view (and I can easily demonstrate it with eye test over exactly same operations ...)

Flash ... maybe

The world #1 plugin sucks for mobile ... not all of them, but still sucks. At least the render is faster via bytecode than canvas one could be, but since we have HTML5 video element as well and since the interaction in a small screen cannot contain all those details and cool effects that Flash has given us 'till now, I don't think Flash should be considered mandatory for a mobile experience ... still, if present, Flash could be our best friend as fallback for all those "not implemented yet" HTML5 features (or in some case, give us even more ... accordingly with security risks we may face).

Gestures ... if any ...

I still don't know how to pronounce this word properly ... but it does not matter.
The only browser able to expose properly gesture and to make developers life easy is Safari Mobile. Even if all recent smartphones support gestures on OS level, this topic seems to be the most complicated thing ever to expose through the browser.
The problem number one is the conflict that these events could cause with System Gestures. If I think about Palm Pre 2 "cards" interaction and the way I love to use this phone, I can instantly imagine how many side effects "my own gestures" could cause from UX perspective ... specially if I am able to avoid System gestures defaults. The problem number two is that we may find gestures variants, just to make our life, as developers, more interesting ... isn't it? Well, as soon as these variant will be part of the newer browser version we can find on these devices, I will dedicate a post about them ... so, patience is the key! (isn't it Weronika :P)
However, if touches events are exposed correctly, some crazy dude out there (and I am not excluding me) could implement gestures through touches events.
gesturestart is when touch list length is greater than 1, gesturechange is only if gesturestart has been fired and both scale and rotate are simple Math operations, while gestureend is fired when the touch list length goes down to 1 or 0 ... almost easy stuff, we don't really need them as long as touches work.

Opera Mobile

This is a must have browser if you want a common cross device web experience or a better browser than the one you have preinstalled in that phone.
Opera Mobile does not expose touches or gestures and the interaction is compromised but as render engine and web surfing, it is a pretty damn fast and cool browser that will be hopefully installable in the most recent Windows Mobile OS, since this has the worst browser you could ever imagine, compared with all others.

Mozilla Fennec

This is in my opinion too young and too featureless to compete with WebKit based implementations first and Opera Mobile after. Mozilla guys are working harder and improving a lot ... but still too much to do and hopefully a stable and cool release before next summer?

Nothing Else

Starting from the fact I could not test all of them, and ppk is here again the man you are looking for, all I can say is that the only superior mobile browser is WebKit based, no matters which branch, as long as things I have talked about are, more or less, supported.

Marry Christmas Everybody