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

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

Monday, November 01, 2010

UX vs IP Based Language

I start being sick of this epic fail and many famous website do this ... I am Italian, I am living in Germany, but my OS as every software or device I have is in English ( and I don't know German yet ) !

The Problem

If you live in your country and you have software in your own language, you probably never spotted what I am talking about. Actually, what you have probably appreciated instead, is the fact if you write in your url bar www.google.com you'll find directly the one translated and relative to your country ... how cool is it?
My tiny winy problem is that if I write the same right now, I am redirected to google.de .... most likely in German with all settings in German as well, even the confirm button, no matter if I managed somehow to reach that point and changed the language ...

How Difficult Is It

Every single fucking browser sends an Accept-Language header with 99.9% of the time the current browser language or, in the worst case scenario, the Operating System one.
If it's not about the server, we have the same behavior on the client via navigator.language ...
In both cases I am sending a bloody en-us string that cannot surely be confused with de-de one, isn't it? But it does not matter, in 2010 and its growing globalization, these "clever" websites still rely on IP address to define the spoken language, but how wrong is this?

Language IS Context Dependent

Let's imagine we are simply traveling ... OK? Good, We have hot spots services in the airport or we are having a coffee in some local chain with wireless connection ... OK? Now we try to visit websites we use to check from home, from our country, and never with a single problem, cookies or not .... we are in the cloud, the one we would like to use everywhere but being behind some other IP address, the cloud does not recognize us anymore ... still cool, uh?
In few words, if we are simply surfing the web there is no reason in this world to trust the current provider for our spoken language.

Location And Laws Context

There are mainly and only two reasons our IP address should be considered, a map application unable to use the W3C Geolocation API, so we are more into a fallback situation, or country laws for all those services that may works differently accordingly with current country (e.g. YouTube)

Everything Else Is UX

If the website we use on daily basis does not recognize us instantly we may feel that something went terribly wrong, isn't it? And how many could freak out the moment even few links around a search field are in a completely extraneous language?
Moreover, if I decided to use English software, rather than italian, it means I made a choice and surely I cannot really complain if websites are always in English even if I am in italy or Germany ... it's the other way round: I expect this, and I am instantly confused the moment this does not happen.

The Failing Google Chrome Attempt

The ridiculous part of this story is an evident UX conflicts inside Google teams, the search engine and the translation one.

In my case, if I start Google Chrome and I go to google.com I am:
  1. redirected into google.de, it does not matter if I explicitly typed .com
  2. the whole search engine in in German
  3. a top bar lazily informs me that the page is in German, would you like to translate?
Oh ... Really??? So the browser understands I am based on English but the server of the same company decided I am German ... how cool is it?
The company that more cares of performances is doing a redirect, a lazy navigator.language analysis, in order to help me with the wrong choice made by the server ... and guess what? The translation team is not brilliant, is everything else that looks dumb!
It must be said that at least I have a Google in English link easy to spot ... but many other sites don't!

User Agent Myths

A user agent should follow W3C standards and AFAIK all do, more or less. It is not about the browser, the platform, it is simply about the only thing that I do believe is consistent across every platform: the language. Of course it's easy to hack a userAgent in order to show a different language ... but who the hell gonna do it for daily browsing? Even the IP could be hacked via userAgent, the one that sends it, isn't it? So why on earth people adopted such silly strategy to define the user language?

The Internet Cafe Context

If we are still thinking about edge cases ... believe me, these are truly rare. Even an internet cafe, most of the time populated by foreigners, could simply create accounts and most used languages set for each account. As example, we could have the user English, the user Deutche, the user Italiano, etc etc ... and the moment we login with this user the OS, and hopefully the software, will be presented in the same language. At that point, every website that will present content based on IP language could be easily labeled as dumb, because in this world were everybody travels and therms as mobile are used on daily basis by marketing, companies behind the same marketing do not get it: it's NOT about the IP!

Monday, October 25, 2010

JavaScript Coercion Demystified

This post is another complementary one for my front-trends slides, about performances and security behind sth == null rather than classic sth === null || sth === undefined.
I have already discussed about this in my JSLint: The Bad Part post but I have never gone deeper into this argument.

Falsy Values

In JavaScript, and not only JavaScript, we have so called falsy values. These are respectively: 0, null, undefined, false, "", NaN. Please note the empty string is empty, 'cause differently from php as example, "0" will be considered truish, and this is why we need to explicitly enforce a number cast, specially if we are dealing with input text value.
In many other languages we may consider falsy values even objects such arrays or lists:

<?php
if (array())
echo 'never'
;
?>

#python
if []:
print 'never'


Above example will not work in JavaScript, since Array is still an instanceof Object.
Another language that has falsy values is the lower C, where 0 as example could be considered false inside an if statement.
Falsy values are important to understand, specially if we would like to understand coercion.

About Coercion

In JavaScript world, coercion is considered a sort of evil and unexpected implicit cast, while in my opinion it's simply a feature, if we understand it and we know how to use it.
Coercion is possible only via == (eqeq) operator, but the thing is that everything is properly implemented cross browsers accordingly with ECMAScript 3 Standard.
This is the scary list newcomers have probably never read, directly from the even newer ECMAScript 5 specification, just to inform you that coercion will hopefully always be there, and nothing is evil.

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as
follows:


  1. If Type(x) is the same as Type(y), then

    1. If Type(x) is Undefined, return true: undefined == undefined

    2. If Type(x) is Null, return true: null == null

    3. If Type(x) is Number, then

      1. If x is NaN, return false: NaN != NaN

      2. If y is NaN, return false: NaN != NaN

      3. If x is the same Number value as y, return true: 2 == 2

      4. If x is +0 and y is −0, return true: 0 == 0

      5. If x is −0 and y is +0, return true: 0 == 0

      6. Return false: 2 != 1


    4. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false: "a" == "a" but "a" != "b" and "a" != "aa"

    5. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false: true == true and false == false but true != false and false != true

    6. Return true if x and y refer to the same object. Otherwise, return false: var o = {}; o == o but o != {} and {} != {} and [] != [] ... etc etc, all objects are eqeq only if it's the same


  2. If x is null and y is undefined, return true: null == undefined

  3. If x is undefined and y is null, return true: undefined == null

  4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y): 2 == "2"

  5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y: "2" == 2

  6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y: false == 0 and true == 1 but true != 2

  7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y)

  8. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y): ToPrimitive means implicit valueOf call or toString if toString is defined and valueOf is not


About last point, this is the object coercion we are all scared about ...

var one = {
valueOf: function () {
return 1;
},
toString: function () {
return "2";
}
};

alert(one == 1); // true
alert(one == "2"); // false

If we remove the valueOf method, we will implicitly call the toString one so that one == "2" or, more generally, {} == "[object Object]".

null == undefined And null == null, Nothing Else!

99% of the time we do a check such:

function something(arg) {
if (arg === undefined) {
}
}

We are asking the current engine to check if the undefined variable has been redefined in the current scope, up to the global one, passing through all outer scopes.
Even worse, we may end up with the most silly check ever:

function something(arg) {
if (arg === undefined || arg === null) {
}
}

which shows entirely how much we don't know JavaScript, being the exact equivalent of:

function something(arg) {
if (arg == null) {
}
}

with these nice to have differences:

  • null cannot be redefined, being NOT a variable

  • null does NOT require scope resolution, neither lookup up to the global scope

The only side effect we may have when we check against null via == is that we consider for that particular case null and undefined different values .... now think how many times you do this ... and ask yourself why ...

Performances

Once again I send you to this simple benchmark page, where if you click over null VS undefined or null VS eqeq, or one of the lines showed under the header, you can realize that while it's usually faster and safer, it provides even more control when compared against the ! not operator.
The only way to reach better performances when we mean to compare against an undefined value in a safer way is to declare the variable locally without assigning any value, so that minifiers can shrink the variable name while the check will be safer.

// whatever nested scope ...
for (var undefined, i = 0; i < 10; ++i) {
a[i] === undefined && (a[i] = "not anymore");
}


There Is NO WTF In JavaScript Coercion!

Coercion in JavaScript is well described and perfectly respected cross browser being something extremely simple to implement in whatever engine. Rules are there and if we know what kind of data we are dealing with, we can always decide to be even safer and faster.
Of course if we are not aware the strict equivalent operator === is absolutely the way to go, but for example, how many times you have written something like this?

if (typeof variable === "string") ...

being typeof an operator we cannot overwrite neither change, and being sure that typeof always returns a string there is no reason at all to use the strict eqeqeq operator since String === String behavior is exactly the same of String == String by specs.
Moreover, as said before, coercion could be absolutely meant in some case, check what we can do with other languages, as example:

# Python 3
class WTF:
def __eq__(self, value):
return value == None

# Python 2
class WTF():
def __eq__(self, value):
return value == None

# in both cases ...
if WTF() == None:
"""WTF!!!"""

While this is a C# example:

using System;

namespace wtf {

class MainClass {

public static void Main (string[] args) {
WTF self = new WTF();
Console.WriteLine (
self ?
"true" : "false"
);
}
}

class WTF {
static public implicit operator bool(WTF self) {
return false;
}
}

}

Can we consider some sort of coercion latest cases as well? It's simply operator overloading, virtually the same JavaScript engines implemented behind the scene in order to consider specifications points when an eqeq is encountered.
Have fun with coercion ;-)

Sunday, October 24, 2010

The Layer ... Of The Layer ... Of The Layer ...

When I read tweets like this one I cannot avoid a quick comment but the reason I am posting, is simply to explain that every time we write a web page/application, we are dealing with at least 4 different layers.
Moreover, this post is complementary for few slides I have introduced at front-trends, specially regarding the "avoid classic OOP emulation when not necessary" point.

Layer #1: JavaScript Libraries

We all know the DOM is a mess, and this is most likely the reason we chose a JS library rather than deal directly with possible problems we can have when we develop an x?HTML page.
Even if many developers don't care, I keep saying that every millisecond gained in this first layer, the page itself, is important.
Moreover, if we have a good understanding of the JavaScript programming language, we can easily realize that all these "Java Pretending Style Frameworks" emulating classic inheritance and OOP are not easier to maintain neither faster for what we need on mobile devices, included Netbooks.
The "easier to maintain" fuzz, associated with "Java style JavaScript", a sentence that does not make sense itself, is only a Java developer point of view.
Well written JavaScript without any "wannabe another language" pragmas, is truly much easier to both understand and write, modify, or fix, while the great magic behind this or that framework/library could become our first enemy when something goes wrong and we would like to understand and debug that magic 'cause we had a problem and we have strict deadline that may not match with a bug lifecycle.
Finally, as easily demonstrated via this test page, we can all spot how much more it costs to simply initialize a new instanceof constructor, compared with proper way to go natively via JavaScript, in that case made easier by this essential script, developed following TDD and tested here cross browser.
Anyway, common sense first and fast production quality, should always be kept in mind when we decide an approach, rather than another one. So, here frameworks play usually quite good role, the one to bring same functionality cross browser.
But what is a browser?

Layer #2: The Browser

As libraries are considered an abstract way to reach same goal in all browsers, browsers are simply abstract applications able to bring the web cross platform.
This is were the browser speed may vary, accordingly with the platform, and were every technique able to speed up render ( DOM+CSS engine such Gecko, Trident, others ) and JavaScript ( engine a part such V8, JavaScriptCore, SpiderMonkey ) is more than welcome. These guys are implementing any sort of trick to make the page and the code that fast, even if they have to deal with different operating systems. And guess what is an operating system?

Layer #3: The Operating System

We are even lucky if the browser deals directly with the operating system graphic API, since many other middle layers could be part of this stack ( flash or third parts plugins, as example ).
You cannot expect that Linux, Mac, and Windows, just mentioning fews Desktop related ( more choices on mobile world ) magically display and provide browser functionalities via the same API. We would need something like a jOSQuery library here to make it happens ... but even worse, every operating system may have another abstract layer able to use, as example, Hardware Acceleration.

Layer #4: The Hardware

Open GL ES 2.0 is simply another abstraction able to transform API calls into specific hardware driver calls which means that starting back from the DOM and the used WebGL or CSS3 with HW support, things have been modified, translated, re-created at least a couple of times.
In few words, if we asked too many things to do on first abstract layer, and being the first the slower one, nothing can be that fast.

As Summary

We, as web or scripting programming languages developers, rarely think that performances on the highest level ever can be that important but unfortunately, that highest level is the slowest one ever so, specially if we would like to reach best frame rate via canvas, WebGL, or CSS3 animations, it's highly recommended to be sure that the strategy/code we are using is the best one for our requirements.
As example, if we spend just a millisecond more to create each object we need for a single frame, we can easily switch from 30fps, a decent visual framerate, to 29 or less, were things will start to be visually slower for our eyes ...
Finally, kudos for Opera Mini and its growing market share, I am pretty sure it will become soon the IE for mobile platforms, making developers life easier, being a portable browser fallback for whatever website or application, hoping will not have all IE problems we all know.

Thursday, October 21, 2010

Front Trends 2010 - My Talk

My talk is finished, there were probably too stuff to talk about and it was hard to make a clear point, but I am willing to better explain myself posting here about main points.

Slides without me trying to show stuff online do not probably make much sense but these are here: ft2010 WebReflection Slides

The benchmark I have showed that should run in any browser ( at least those A grade ) is here. During this talk I have tried to explain what each test means. You can grab the benchMark function from the source, it's simple but it ruffling did the job.

The showed "problematic parent" example is here.

Tests for my essential Class are here.

Talk Summary


I have tried to explain that sometimes we should take care of performances techniques, accordingly with the goal and the target.
I have showed how things could go slow in whatever Netbook, regardless hardware acceleration.
What I have not been probably able to explain , is that it's up to our common sense decide when we should avoid common good practices or not, and I won't link here the IE9+iPhone/iPad canvas experiment since I would like to talk with openstreetmap.org guys before and eventually create a proper GitHub project for their slickviewer, mobile version.

Thanks everzbody for listening, all the best.

Sunday, October 17, 2010

Pre Authorization Meta Tag Proposal

Under the HTML5 flag, browsers are bringing to our desktops or devices exciting features such GeoLocation, File, and many others such camera, microphone, system access, etc ...

The Problem

While this is good from possibilities point of view, the activation approach historically sucks. Flash and it's video or microphone activation shows a dialog that asks the user to authorize media access while browsers are lazily asking via JavaScript the same. The real life scenario we all know is definitively different when a page is using a screen reader, and this article and video about twitter UX should be enough to open our eyes: something is wrong.

Solutions

If we ever used an Android device, or we have download applications from whatever mobile store, we should be familiar with the installation warnings and confirmations we suppose to read and accept in order to grant application access to anything it needs to work properly.
This simply means that once we accept we won't be bothered anymore and the application can easily work as expected.
It's all about privileges and in my opinion it would be nice to have similar approach in our browsers as well, also to make web application even closer to native one.


Proposal

Following the "don't break the WEB" approach, all we could do is put a meta tag, as we do for viewports, specifying all those Technologies/API we would like to use in our webpage. This is an example:

<meta name="grant" content="GeoLocation,Camera" />
<meta name="grant" content="System" />

The proposal should ask at the very beginning and only once if the webpage could access these functionalities and the user can decide before what should be available and what should not.
The "before" action is important 'cause in this Ajax era it's extremely easy to loose focus runtime with whatever activation request and this is so wrong.
The list of granted API should be reachable via userAgent via specific method such:

navigator.hasGranted("GeoLocation")

or similar, so that eventually we can decide via JavaScript if we would like to ask again runtime, as we do now, or simply provide an alternative solution or message, maybe showing an "ask again to activate" button, remembering to put back the focus in the right context.

Alternative

Web developers could implement similar concept asking with the very first script access to one or more API and put the page focus back. With GeoLocation, as example, the user will chose immediately his preferences without having surprises in the middle of a session, or later.

// As Soon As Possible
var HAS_GEO_LOCATION = false;
try {
navigator.geolocation.getCurrentPosition(function (result) {
// so that other scripts could check if already available
HAS_GEO_LOCATION = true;
// notify the event in any case
var evt = document.createEvent("Event");
evt.initEvent("geolocationready", 1, 1);
evt.data = result;
// implicit window context
dispatchEvent(evt);
});
} catch(e) {}

A usage example could be something like:

// script loaded after a while ...

if (HAS_GEO_LOCATION) {
doFreakingCoolStuffWithGeo();
} else {
addEventListener(
"geolocationready",
doFreakingCoolStuffWithGeo,
false
);
}


We can eventually specify the handleError callback as well but actually this is part of the HAS_GEO_LOCATION value, if there is an error no reason to insist, simply assume that there is no geo location and go with the fallback, if any.

What do you think?

Friday, October 15, 2010

Technical Reviews: Bestsellers!

Just a quick one about two technical reviews out of two I have recently done for @stoyanstefanov and @cjno for these completely different books: JavaScript Patterns and Test-Driven JavaScript Development.

Right now these are both Top 10 Bestsellers and trust me: other JavaScript Jedis have been involved, you won't regret these lectures! ;-)



Tuesday, October 05, 2010

JavaScriptCore via Terminal

Just a quick one, maybe only for a new Mac comer as I am, I found truly annoying I have already Python, Ruby, and even PHP everywhere available in my command line but not JavaScript?

What The Fuck

Even Windows runs .js files natively and since ages, I wonder why on earth after I have downlaoded the whole XCode SDK "my JavaScript" was not there available for all my needs.

OK, OK, node.js is already on /bin, linked and working properly, but now I have the system default JavaScript Engine that comes automatically with WebKit or the "IE for Mac" aka Safari.

How to link jsc to bin folder

A title that produces zero outcome on Google, could be hopefully better addressed via this blog, and this is how I have solved:

sudo ln -F /System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc /usr/bin

The Current folde ris the link to the latest one, all those threads about the ..../A/... folder are not automatically updated if A becomes B, as example.
So, now I can type jsc wherever I am and use JavaScript power whenever I want, writing just quit() anytime I need.
I hope this helps, it took a while for me to sort it out.

Saturday, October 02, 2010

Apple UX Fails with Mac Mini

Update
Following Daniel suggestion (first comment), I have grabbed a cabled keyboard and a cabled mouse from a colleague and I have been able to finish the initial procedure. Happy to be a Mac Mini user now, it works like a charm!


as tweeted already, apparently there's no way I can buy a dishwasher. Last time I almost came back home with a pretty cool Samsung Blue Ray Player ... but I bought nothing, this time I did a mistake: I bought a Mac Mini.
The time my new Mac Mini has been switched on is no longer than 10 minutes, and right now I am still unable to use it ... and I would like to tell you the story ...

Nothing On The Package

It's clean and small, no requirements or dependencies specified anywhere. Being the package obviously close, I have not been able to RTFM.
The only thing I took care of was the absence of the HDMI cable ... not a big deal, I have bought one and this, at least, works like a charm!

Pretty Cool And Useless Gadgets

Wireless keyboard and wireless trackpad, these gadgets are a must have for my room configuration: a 32" LED Sony Bravia screen with Full HD capability and a comfortable (and cheap) sofa about 1 meter far away from the screen. The plan was perfect, the result still a disaster.

Totally Stuck On First Run



As you can see from this picture, there is nothing I can do. Trust me, both keyboard and trackpad are switched on, and the lovely King of Operating Systems is unable to recognize them and, for this reason, unable to let me use the consistent amount of money I have spent few minutes before.

Epic Fail

All Apple gadgets and products come ready and easy to use, this is a key for this company and the reason I gave up trying to avoid its products ... these are simply great.
I could never expect such problem using all official Apple/Mac stuff, and if this is a known issue either a marketing strategy (I should buy a mouse now, uh? I won't!) it's a massive hole in the whole UX excellence we think when we talk about Apple.
Please put massive cubic labels over each Mac Mini saying: without our mouse, you can't do anything!

wru against wru: version 1 ready

This shot has been token on 13th September 1923, when W.H. Murphy demonstrated the efficiency of his bulletproof vest, the one that sold later to NY Police Department.

Above image has been historically used for different topics and the current one is "how much we trust what we sell".

Do You Trust Your UT Framework?

I wasn't kidding that much when I wrote about "test the testing framework" in my precedent wru post. The overall Unit Test Frameworks code coverage is poor, specially those with all the magic behind the scene, magic that does not come for free.

Use The Framework Itself To Test The Framework

This is a common technique that may result in a reliability deadlock. If we trust our UT Framework and we use it to test itself, the moment we have a problem with the framework we'll never know ... or even worst, it will be too late.

Don't Trust "Magic" Too Much

If the framework is simple and it does not pollute each test with any sort of crap, we can surely use it to test the framework itself without problems while if this framework elaborates and transforms our tests, it may become impossible to test it via the framework itself due scope and possibly context conflicts for each executed test.
This may produce a lot of false positives for something in place theoretically to make our code more robust.

The wru KISS approach

With or without async.js, wru does few things and now it's proved that it does these things properly. I don't want to spend any extra time for a library that I should trust 100% and if I know that all things this library should do are working as expected, I can simply "forget to maintain it" (improve, eventually) and use it feeling safer.

99.9% Of Code And Cases Coverage

Loaded on top of whatever test, wru uses few native calls and the assumption is that these are already working as expected (accordingly with ES3 or ES5 specs).
The new wru test against wru covers all possible tests combination, where setup and teardown could fail on wru itself or for each test, and assert should simply work in a test life-cycle. This means we could assert inside setups and teardowns as well, simply because these calls are fundamental for a single test and, if present, must be part of the test result. A problem in a setup could compromise the whole test while a problem in a teardown could compromise other tests. Being sure that nothing went wrong is up to us but, at least, we can do it via wru.

Can you do the same with your UT Framework? Do you have the same coverage? Have fun with wru ;)