Dojo 0.4 has been released and one of its new features is a clock widget ... a clock widget ? ... Yes, a "fantastic" JavaScript Client Time based clock widget !!!
Hey Dojo developers, why do you think that OS (bottom right) clock isn't enought ?
It seems that Web 2.0 is going to be the new Flash 5 of the net ... I don't like it!
Ok, your framework is amazing, your code is fantastic ... but I wonder who need another JS clock ?
Is this server-side Greenwich time based ? None ...
Can I flip something inside that to set an appointment ? None ...
... then I can understand You only if it's a SVG demo (However, who care about my opinion ?)
Finally, since it's time to create clock widgets, I've decieded to waste my time with a basic digital clock and sure ... if you add some hour you could have different times too ...
This is my "fantastic" digital clock ... (LOL)
P.S. hey guys, it's only a joke :D
behind the design
My JavaScript book is out!
Don't miss the opportunity to upgrade your beginner or average dev skills.
Wednesday, October 25, 2006
Monday, October 23, 2006
Some valid reason to hate IE7
I don't like IE, and I don't like new 7 version too and I would like to create a page that will work with every other updated browser but obviously not with IE7 ... our new web development bottleneck !!!
P.S. Please, Microsoft, remove IE7 as default browser from Windows Vista when it will be available ... and let users choose the best way to surf the web 2.0, thank you.
P.S. Please, Microsoft, remove IE7 as default browser from Windows Vista when it will be available ... and let users choose the best way to surf the web 2.0, thank you.
Friday, October 20, 2006
Unobtrusive JS Pixel Font (Round 2)
If you dont' know why this is the second round You should read this post and its comments .
This is the round 2, or better, the final round for my Pixel Font Engine, now totally based on CANVAS and DOM or based on SWF OBJECTS and one innerHTML for old deprecated browsers or Internet Explorer (really it cames with new version 7 and in WEB 2.0 era it doesn't support canvas ... damn IE7 !!! Why You should use them ?)
new concept
CANVAS or Flsh Player 6 dedicated SWF to render Pixel Font table Objects, because old version was really too mush slow and because canvas are better than nested tables to draw something (and Flash 6 can draw something well too).
Why I've not used VML or other fake canvas for IE ? Because I've tested them and they're all slow for this kind of interaction and excanvas render single pixels in a bad, bad, bad, way ... thery're unreadable !!!
Well, now You can't parse entire page but you can use this font or others created by yourself using pixel font generator ... and, have fun with pixel fonts :)
Here there's a shot of what You should view after onje click on DEMOSTRATION (... and another click to back to normal version)
This is the round 2, or better, the final round for my Pixel Font Engine, now totally based on CANVAS and DOM or based on SWF OBJECTS and one innerHTML for old deprecated browsers or Internet Explorer (really it cames with new version 7 and in WEB 2.0 era it doesn't support canvas ... damn IE7 !!! Why You should use them ?)
new concept
CANVAS or Flsh Player 6 dedicated SWF to render Pixel Font table Objects, because old version was really too mush slow and because canvas are better than nested tables to draw something (and Flash 6 can draw something well too).
Why I've not used VML or other fake canvas for IE ? Because I've tested them and they're all slow for this kind of interaction and excanvas render single pixels in a bad, bad, bad, way ... thery're unreadable !!!
Well, now You can't parse entire page but you can use this font or others created by yourself using pixel font generator ... and, have fun with pixel fonts :)
Here there's a shot of what You should view after onje click on DEMOSTRATION (... and another click to back to normal version)
Tuesday, October 17, 2006
JavaScript Pixel Font Generator
One of the coolest things of generic Flash textFields are pixel fonts.
I love those tiny smally colly fonts ... that's why I've decieded to create a pixel font render engine.
concept
matrix and grids ... sure, and if You think that a grid "is a table" you've just found the render engine concept:
a lot of table cells with or without a background color.
Since the better way to draw something on web pages is a nice CSS style, created tables are quite totally CSS based, then You can joke with cell width, height, padding, spacing and colors and then You can have different effects with a single font table.
This strange object will contain one or more dedicated cell string that you can create using a really simple SWF GUI application like this one, then everyone should have a personal JavaScript pixel font * :)
Pixel Font Render class will use these information to create a lot of string dedicated for an innerHTML interaction.
Why innerHTML ?
I'va a personal DOM based version of render engine but for some reason IE (7 too) didn't creates as expected runtime tables as FireFox or Opera 8 did.
Another reason is that DOM isn't faster as innerHTML and multiple elements creation should be a browser killer.
Why You wrote "be sure to use a fast browser" ? Are there limits ?
Tables are not really performances friend, then You can't use this engine to replace every string in your web pages because any browser could manage big big tables quickly.
(then) What js pixel font should be used for ?
Use your immagination but I just could tell you these things:
... and probably more.
If You've not viewed the example page (or You didn't understand how does it work) You could clik this link and then You can click DEMOSTRATION header.
Please be sure You're not using an old browser or an old PC, that page should stress old hardware :(
* please, send me Your pixel font to create a demostration page with different fonts and to allow users to download one of them
I love those tiny smally colly fonts ... that's why I've decieded to create a pixel font render engine.
concept
matrix and grids ... sure, and if You think that a grid "is a table" you've just found the render engine concept:
a lot of table cells with or without a background color.
Since the better way to draw something on web pages is a nice CSS style, created tables are quite totally CSS based, then You can joke with cell width, height, padding, spacing and colors and then You can have different effects with a single font table.
This strange object will contain one or more dedicated cell string that you can create using a really simple SWF GUI application like this one, then everyone should have a personal JavaScript pixel font * :)
Pixel Font Render class will use these information to create a lot of string dedicated for an innerHTML interaction.
Why innerHTML ?
I'va a personal DOM based version of render engine but for some reason IE (7 too) didn't creates as expected runtime tables as FireFox or Opera 8 did.
Another reason is that DOM isn't faster as innerHTML and multiple elements creation should be a browser killer.
Why You wrote "be sure to use a fast browser" ? Are there limits ?
Tables are not really performances friend, then You can't use this engine to replace every string in your web pages because any browser could manage big big tables quickly.
(then) What js pixel font should be used for ?
Use your immagination but I just could tell you these things:
- web page decorations
- menu customizzation
- graphic enanchment
- dynamic Chapcha
- footer pages informations
- header titles
... and probably more.
If You've not viewed the example page (or You didn't understand how does it work) You could clik this link and then You can click DEMOSTRATION header.
Please be sure You're not using an old browser or an old PC, that page should stress old hardware :(
* please, send me Your pixel font to create a demostration page with different fonts and to allow users to download one of them
Thursday, October 12, 2006
JavaScript Path Finder with A Star
Last post talks about a stupid tris game and while I was writing that code I've thought about a way to create a better script (more intelligent).
Since tris game, as many others, is based on a grid, I've looked for one A * JavaScript implementation but hey, I didn't find them !
I remember Alessandro did a path finder for ActionScript and as you know AS is ECMA and its A Star implementation should work on JavaScript too.
However, Flash has a dedicated virtual machine (Flash Player) and its source is byteencoded, then AStar is fast enought but not so fast used with JavaScript.
That's why I've decieded to create a generic AStar function quite optimized for JavaScript (but it probably should be better too) and usable with ActionScript 1.0 too.
Here there's a simple application example while in this page you can read about the function and view the source code too.
Example uses a MemTronic version to reduce AStar size into 1,4 Kb.
Finally, this is the "old" Alessandro implementation where you can find more informations about A Star algorithm :)
Since tris game, as many others, is based on a grid, I've looked for one A * JavaScript implementation but hey, I didn't find them !
I remember Alessandro did a path finder for ActionScript and as you know AS is ECMA and its A Star implementation should work on JavaScript too.
However, Flash has a dedicated virtual machine (Flash Player) and its source is byteencoded, then AStar is fast enought but not so fast used with JavaScript.
That's why I've decieded to create a generic AStar function quite optimized for JavaScript (but it probably should be better too) and usable with ActionScript 1.0 too.
Here there's a simple application example while in this page you can read about the function and view the source code too.
Example uses a MemTronic version to reduce AStar size into 1,4 Kb.
Finally, this is the "old" Alessandro implementation where you can find more informations about A Star algorithm :)
Tuesday, October 10, 2006
A simple JavaScript game to waste Your time
A pool ? A web service ? A fantastic UI ? ... no, it's just a simple and fast way to waste Your time online, it's just a stupid JavaScript Tris Game :)
Here the source, have fun !
Here the source, have fun !
Thursday, October 05, 2006
bytefx V 0.3 final
New API since it's a young library and I suppose is better to have a final release before someone will use them.
Now, better code, better comments, better api, linear methods, real private methods, rewrote drag with new features ... in the same compressed version size, less than 2Kb for MemTronic version !
It's bytefx ... version 0.3 final (if this hasn't bugs, this will be exactly in this way)
Now, better code, better comments, better api, linear methods, real private methods, rewrote drag with new features ... in the same compressed version size, less than 2Kb for MemTronic version !
It's bytefx ... version 0.3 final (if this hasn't bugs, this will be exactly in this way)
Tuesday, October 03, 2006
Packer Friendly JavaScript
Mario tells me a thing on this post comments that could be a good point to analyze.
Since I've known Dean Edwards packer, I've started to write code in a different way.
The reason is simple: code is elegant enought and I could pack or unpack them quickly.
The "big one rule" to write compressors friendly code is the usage of the semi-colon ";" instead of new line at the end of each line (sure, only where it's necessary).
In this way your code could be crunched without problems from a big list of js compressors.
Let me show an example
These functions are not a problem for javascript parser because it reads new lines as semi-colon (or better ... as end points) but to be sure that a compressor will not have problems, You need to think that every code must be parsed correctly inline, trimming every space or tab.
In this case, function a has no problems while function b has one.
There's any end char after c var, then creturn is not c and then return.
What is the solution ? You know it, just a semi-colon :)
return c doesn't need any semi-colon because curly brackets tells to code parser that in that point the execution ends.
If You have an if, while, else if, else, for You don't need to add anything before last curly bracket.
But if You don't use curly brackets for single operations after some expression, the use of semi-colon is a must.
I think is really important to remember that there is a particular case where curly brackets requires a semi-colon at the end and this case is a generic object declaration.
If you need more than one temporary scope variable you could use the colon "," to concatenate each var declaration.
In this case the semi-colon is not necessary between two variables.
That's all about curly brackets but I would suggest to use a semi-colon after every end bracket "}", to be sure that there aren't problems and to write a more linear code.
Talking about vars You can see that a semi colon is necessary after each declaration.
And as I've said, using a colon for each temporary var requires a semi-colon only at the end.
Other characters that require a semi-colon at the end are parentheses.
Sure, semi-colon is not necessary if you send anonymous function to another one but in other cases is really important to rememeber that every end parenthese ")" needs a semi colon, such at the end of this alert example.
With class object declaration You could forget parenthese but these should be wrote at the end of class name, then rememebre to add a semi-colon.
I think there's only last case where semi-colon is necessary and this is the switch operator.
Only the last break could be wrote without the semi-colon, because as is for everything before each end curly bracket "}".
The final point is that semi-colons are javascript friends, then is always better one more than one miss.
I think this is all you need to know about compressors friendly code and as You can see adding just a semi colon while You create is neither a bad practice nor less elegant than other ways but Your script will be released as packer ready :-)
[ edit ]
Just a simple addiction that should be a mistake ... with if, else and else if or where curly brackets are more than one operation, You don't have to put any semi colon at the end of closed bracket.
Since I've known Dean Edwards packer, I've started to write code in a different way.
The reason is simple: code is elegant enought and I could pack or unpack them quickly.
The "big one rule" to write compressors friendly code is the usage of the semi-colon ";" instead of new line at the end of each line (sure, only where it's necessary).
In this way your code could be crunched without problems from a big list of js compressors.
Let me show an example
// "typical" code
function a() {
return "a"
}
function b(c) {
c = "b" + c
return c
}
These functions are not a problem for javascript parser because it reads new lines as semi-colon (or better ... as end points) but to be sure that a compressor will not have problems, You need to think that every code must be parsed correctly inline, trimming every space or tab.
In this case, function a has no problems while function b has one.
// function a can be wrote inline
function a() {return "a"}
// function b cannot be wrote inline
function b(c) {c = "b" + creturn c}
There's any end char after c var, then creturn is not c and then return.
What is the solution ? You know it, just a semi-colon :)
function b(c) {c = "b" + c;return c}
return c doesn't need any semi-colon because curly brackets tells to code parser that in that point the execution ends.
If You have an if, while, else if, else, for You don't need to add anything before last curly bracket.
function c(d) {
if(d) {
d = true
}
return d
}
But if You don't use curly brackets for single operations after some expression, the use of semi-colon is a must.
function c(d) {
if(d)
d = true; // remember
return d
}
I think is really important to remember that there is a particular case where curly brackets requires a semi-colon at the end and this case is a generic object declaration.
var obj = {}
var arr = []
// do you need an error ? try this
// var obj = {}var arr = []
// correct way
var obj = {}; // remember
var arr = [];
If you need more than one temporary scope variable you could use the colon "," to concatenate each var declaration.
In this case the semi-colon is not necessary between two variables.
var obj = {}, arr = [];
That's all about curly brackets but I would suggest to use a semi-colon after every end bracket "}", to be sure that there aren't problems and to write a more linear code.
function a(a) {
return a
};
function c(d) {
if(d) {
d = true
};
return d
};
var obj = {}; // remember
Talking about vars You can see that a semi colon is necessary after each declaration.
// not friendly way
var str = "test"
var num = 1
var boo = false
// friendly way
var str = "test"; // remember
var num = 1; // remember
var boo = false; // remember
And as I've said, using a colon for each temporary var requires a semi-colon only at the end.
var str = "test", num = 1, boo = false; // remember
Other characters that require a semi-colon at the end are parentheses.
// anonymous function, not friendly way
(function(){
alert("anonymous")
})()
// friendly way
(function(){
alert("anonymous")
})(); // remember
Sure, semi-colon is not necessary if you send anonymous function to another one but in other cases is really important to rememeber that every end parenthese ")" needs a semi colon, such at the end of this alert example.
alert((function(){return "something"})());
With class object declaration You could forget parenthese but these should be wrote at the end of class name, then rememebre to add a semi-colon.
// generic class
function MyClass(){
this.ready = true
};
// generic class objects
var c1 = new MyClass(),
c2 = new MyClass; // remember
// generic check
alert(c1.ready === c2.ready); // will be "true"
I think there's only last case where semi-colon is necessary and this is the switch operator.
// not friendly way
switch(true) {
case false:
break
default:
alert("true");
break
};
// friendly way
switch(true) {
case false:
break; // remember
default:
alert("true");
break
};
Only the last break could be wrote without the semi-colon, because as is for everything before each end curly bracket "}".
The final point is that semi-colons are javascript friends, then is always better one more than one miss.
I think this is all you need to know about compressors friendly code and as You can see adding just a semi colon while You create is neither a bad practice nor less elegant than other ways but Your script will be released as packer ready :-)
[ edit ]
Just a simple addiction that should be a mistake ... with if, else and else if or where curly brackets are more than one operation, You don't have to put any semi colon at the end of closed bracket.
if(something) {
test = true
} // remember no semi-colon
else {
test = false
};
try {
something()
} // remember no semi-colon
catch(e) {
alert(e);
};
Monday, October 02, 2006
google world, world wide or world wide web ?
It's just a funny post about a strange thing happened just 5 minutes ago ... I need to change my keyboard because it often misses some char, however I was looking for an Italian site when I've quickly digited ww.google.it ...
I read url error but connection was working ... then, what's up ? Google has a personal ww prefix ?
It's really strange, maybe my friend FireFox did it for me ... but hey, it's the same with my enemy IE 7RC1 ... and Opera opened them too !!!
... but, wow, this happen with a single w too, http://w.google.it/ ... and if I search something this work as www.google.it ... Ok, Ok, the world changes too fast and I'm not updated, let me try w.devpro.it .... error ? Why error ?
Why google has 4 ways to be open while every site I know has a maximum of 2 ways ? (site.it, www.site.it)
I don't know if this is a news, I don't know if You known it but I know that google.com doesn't work in this way (but there's a redicert if you try with a single or double w).
It's strange for me and maybe I need to rewrite every url parser that accept http:// or www[0-9]+\. $name .... he he he, who have an updated compatible reg-exp ? :P
I read url error but connection was working ... then, what's up ? Google has a personal ww prefix ?
It's really strange, maybe my friend FireFox did it for me ... but hey, it's the same with my enemy IE 7RC1 ... and Opera opened them too !!!
... but, wow, this happen with a single w too, http://w.google.it/ ... and if I search something this work as www.google.it ... Ok, Ok, the world changes too fast and I'm not updated, let me try w.devpro.it .... error ? Why error ?
Why google has 4 ways to be open while every site I know has a maximum of 2 ways ? (site.it, www.site.it)
I don't know if this is a news, I don't know if You known it but I know that google.com doesn't work in this way (but there's a redicert if you try with a single or double w).
It's strange for me and maybe I need to rewrite every url parser that accept http:// or www[0-9]+\. $name .... he he he, who have an updated compatible reg-exp ? :P
Sunday, October 01, 2006
new bytefx presentation page
JavaScript code is the same, less than 2Kb compressed for a simple effects library, but its presentation page now is better than ever.
Here it is, bytefx, with a simple design and some special effects for compatible browsers.
This page is totally unobtrusive, as bytefx would be, but for compatible browsers it should look cool and it's a new library demo too!
For this new index I've used packer version combined with JSL to have more compatible browsers and to use some JavaScript 1.6 standard and useful methods.
What do you think about this new bytefx site ? I hope you like it and remember thatI'm working on then come back soon to view new contents or examples :-)
Here it is, bytefx, with a simple design and some special effects for compatible browsers.
This page is totally unobtrusive, as bytefx would be, but for compatible browsers it should look cool and it's a new library demo too!
For this new index I've used packer version combined with JSL to have more compatible browsers and to use some JavaScript 1.6 standard and useful methods.
What do you think about this new bytefx site ? I hope you like it and remember thatI'm working on then come back soon to view new contents or examples :-)
Thursday, September 28, 2006
bytefx less than 3Kb ? ... NO, less than TWO !!!!!
What an incredible compressor ... i didn't know it but seems really really a good compressor !!!
I'm talking about memtronic javascript compressor that allows me to pass from about 2.7 Kb into 1.98 Kb (with comments) !!!
Sure, it's not a big difference from Dean Edward packer but now I can say that I've created an FX library in exactly 1.889 byte (without comments) ... it's hilarus for me, I didn't know that some compressor was able to reduce size in this way.
Thank you memtronic !!! Your compressor is fantastic !!!
Here you can find bytefx API page with memtronic version demo and the link under Sources:
bytefx
I'm talking about memtronic javascript compressor that allows me to pass from about 2.7 Kb into 1.98 Kb (with comments) !!!
Sure, it's not a big difference from Dean Edward packer but now I can say that I've created an FX library in exactly 1.889 byte (without comments) ... it's hilarus for me, I didn't know that some compressor was able to reduce size in this way.
Thank you memtronic !!! Your compressor is fantastic !!!
Here you can find bytefx API page with memtronic version demo and the link under Sources:
bytefx
Running with a Number ...
I think this post is only for basic JS developers and shows how a simple function or a simple operation should be wrote in different ways.
In this specific case, I would talk about logic used for a single function while I was optimizing bytefx.
The problem
I've two numbers, x and y, I need to change x, adding or removing a "speed" value, while x is not equal to y.
This simple problem has a lot of solutions. This is probably the simplest one:
As you can see by yourself, this simple function could create a range of numbers from Nstart to Nend.
This is an example:
These operations should be usefull to move an element, to change some value from a startPoint to endPoint ... but, as i've said, there are different ways to do that.
This way is, for me, a better way to write the same function.
Simple ? Clear ? ... I like this way as I like ternary operator, it's a must to write compact but efficient code.
However, look at this last function ... don't You see something strange ?
If and else if do exactly same operations ... only plus sign and greater than are diferent.
How we could create these similar operations in a single line ?
Using eval, sure !
Yess !!! ... seems perfect ? ... or seems the evil ? Let me explain that :)
... simple ? cool ? ... no, it's not cool !
Eval in this case isn't absolutely dangerous or a problem while ternary operator is.
The answer is simple, we have reduced code size with a simple and fast function but we do everytime two operations.
These are x + speed or x - speed in both cases duplicated.
It's true, a simple addiction shouldn't be a problem for code execution, but if there's a way to use a better function, why we shouldn't use that ?
Final solution
We don't care about case x == y but an operation like this one Math.min(1,1) returns 1 and not an error than why we couldn't use ternary operator ?
Do you think this is the best way to run from a Number to another ? I think so :)
In this specific case, I would talk about logic used for a single function while I was optimizing bytefx.
The problem
I've two numbers, x and y, I need to change x, adding or removing a "speed" value, while x is not equal to y.
This simple problem has a lot of solutions. This is probably the simplest one:
function xRun2y(x, y, speed) {
// check wich number is greater than other one
if(x < y) {
// ok, x is less than y ... then add speed
x += speed;
// x can't be greater than y ...
// x can be only less than y ... or equal
if(x > y)
x = y; // stop run
}
// other case, x is greater than y
else if(x > y) {
// well, in this case we remove speed from x
x -= speed;
// but x can't be lower than y ... then ...
if(x < y)
x = y;
}
// we don't need to care about x == y
// just return x
return x;
};
As you can see by yourself, this simple function could create a range of numbers from Nstart to Nend.
This is an example:
// from 10 to 0
var start = 10, end = 0, speed = 1,
arr = [];
while(start !== end) {
start = xRun2y(start, end, speed);
arr.push(start);
};
alert(arr); // 9,8,7,6,5,4,3,2,1,0
// from 0 to 10
var start = 0, end = 10, speed = 1,
arr = [];
while(start !== end) {
start = xRun2y(start, end, speed);
arr.push(start);
};
alert(arr); // 1,2,3,4,5,6,7,8,9,10
These operations should be usefull to move an element, to change some value from a startPoint to endPoint ... but, as i've said, there are different ways to do that.
This way is, for me, a better way to write the same function.
function xRun2y(x, y, speed) {
// check wich number is greater than other one
if(x < y)
// with a ternary operator we can do everything inline
x = x + speed > y ? y : x + speed;
// other case, x is greater than y
else if(x > y)
// well, in this case we remove speed from x
x = x - speed < y ? y : x - speed;
return x;
};
Simple ? Clear ? ... I like this way as I like ternary operator, it's a must to write compact but efficient code.
However, look at this last function ... don't You see something strange ?
If and else if do exactly same operations ... only plus sign and greater than are diferent.
How we could create these similar operations in a single line ?
Using eval, sure !
function xRun2y(x, y, speed) {
var temp = x < y ? ["+", ">"] : ["-", "<"];
return eval("x".concat(temp[0], "speed", temp[1], "y?y:x", temp[0], "speed")); };
Yess !!! ... seems perfect ? ... or seems the evil ? Let me explain that :)
function xRun2y(x, y, speed) {
// we need to create dedicated ternary operation
var temp = x < y ?
// if x is lower than y we need to add speed
// and verify that x + speed is not greater than y
["+", ">"] :
// in other case we need to remove speed from x
// and check if x is not lower than y
["-", "<"];
// if x is lower than y this string is:
// x + speed > y ? y : x + speed
// else if x is greater than y ...
// x - speed < y ? y : x - speed
return eval("x " + temp[0] + " speed " + temp[1] + " y ? y : x " + temp[0] + " speed"); };
... simple ? cool ? ... no, it's not cool !
Eval in this case isn't absolutely dangerous or a problem while ternary operator is.
The answer is simple, we have reduced code size with a simple and fast function but we do everytime two operations.
These are x + speed or x - speed in both cases duplicated.
It's true, a simple addiction shouldn't be a problem for code execution, but if there's a way to use a better function, why we shouldn't use that ?
function xRun2y(x, y, speed) {
if(x < y)
// we need minimum value because
// if x + speed is greater than y
// we want y
x = Math.min(x + speed, y);
else if(x > y)
// we need maximum value because
// if x - speed is lower than y
// we want y
x = Math.max(x - speed, y);
return x;
};
Final solution
We don't care about case x == y but an operation like this one Math.min(1,1) returns 1 and not an error than why we couldn't use ternary operator ?
function xRun2y(x, y, speed) {
return x < y ? Math.min(x + speed, y) : Math.max(x - speed, y);
};
Do you think this is the best way to run from a Number to another ? I think so :)
Tuesday, September 26, 2006
simple effects ? bytefx
... less than 5.50 Kb for the un-packed version, less than 3Kb for Dean's packer compressed version (my php compressor doesn't like it ... and I need to know more about this problem !!! ).
It's bytefx, naturally compatible with FireFox or JS 1.6 standard browsers, compatible with IE5.5 or greater version with my JSL.
I need some day to write the simple API, docs and FAQs ... but you can just view an alpha version in action surfing this demo page.
Seems cool ? Seems another boring FX library ? Seems doesn't work with Safari or other browsers ? (I've not yet tested with Konqueror or Safari)
I don't know what bytefx seems ... but I like it :)
It's bytefx, naturally compatible with FireFox or JS 1.6 standard browsers, compatible with IE5.5 or greater version with my JSL.
I need some day to write the simple API, docs and FAQs ... but you can just view an alpha version in action surfing this demo page.
Seems cool ? Seems another boring FX library ? Seems doesn't work with Safari or other browsers ? (I've not yet tested with Konqueror or Safari)
I don't know what bytefx seems ... but I like it :)
Are speed tests really usefull for developers ?
Yesterday my favourite portal HTML.it has posted a speed test inside its blog.
This JavaScript benchmark was posted on this site.
I think that those kind of tests are only a "point of view" and aren't comparable with real javascript usage.
As I've showed on my for and while loop test, every operation is a single case to analize and every single case has not everytime the same result.
For example using a for and an <= expression with every loop should be faster in some browser and should be slower in some other.
Then it's not always a good way to compare some internal loop operations because a browser should be faster to push a string inside an array but should be slower to execute that kind of for loop.
Often speed depends on garbage collector too, that should be faster in some point of execution and slower in some other.
These concept are true with every other benchmark of that site.
Math engine, as Ajax declaration, are faster with FireFox and really bad with IE because the object has a dedicated try catch for every IE browser.
I usually don't use that way to declare an XMLHttpRequest then my library should be faser than Opera with IE too.
If you change some piece of execution code, you can see that IE6 or 7 is even slower than FireFox with some function.
What I mean is that a real "every day" application will "never" use 4000 try catch but should use a lot of Math operations and DOM elements using many array and Ajax declarations too.
Every Ajax object or class should be simple or really complex and some browser should declare it faster or slower than other one.
Another generic relevant thing is code optimizzation ... you could use "only Opera" to surf the web but if a library contains bad practices its code execution will be slow in every case.
And again, the use of "var" before every temporary variable should be slower or faster, look at the MathEngine function ... is this usefull ?
is this a real application example ?
The StringFuncs has 2 operations that are only for human eyes because if you don't call those functions how can you test them ?
A "StringBuilder" function should be a better test too because every JS developer knows that using string += something isn't a good speed practice and the use of concat instead of '+''+''+''+''+' ... is faster too.
A StringBuilder operation is not different from array.push, but doesn't use sort and reverse as ArrayFuncs does.
Is a StringBuilred competition another usefull test to do ? I think that ...
... and Should we care about few milliseconds ?
Then this is what I think: these speed tests are a must only for Rhino or SpiderMonkey developers because a javascript developer doesn't need to care about performances (in this way) ... He needs to care about generic code optimizzations using lightweight code implementations without redundant operations inside a cross-browser code.
That's what a developer should care about, not dedicated speed test for this or that function.
Finally, this is a revisited version of that benchmark, enjoy with it, don't care about it!
See you :)
This JavaScript benchmark was posted on this site.
I think that those kind of tests are only a "point of view" and aren't comparable with real javascript usage.
As I've showed on my for and while loop test, every operation is a single case to analize and every single case has not everytime the same result.
For example using a for and an <= expression with every loop should be faster in some browser and should be slower in some other.
Then it's not always a good way to compare some internal loop operations because a browser should be faster to push a string inside an array but should be slower to execute that kind of for loop.
Often speed depends on garbage collector too, that should be faster in some point of execution and slower in some other.
These concept are true with every other benchmark of that site.
Math engine, as Ajax declaration, are faster with FireFox and really bad with IE because the object has a dedicated try catch for every IE browser.
I usually don't use that way to declare an XMLHttpRequest then my library should be faser than Opera with IE too.
If you change some piece of execution code, you can see that IE6 or 7 is even slower than FireFox with some function.
What I mean is that a real "every day" application will "never" use 4000 try catch but should use a lot of Math operations and DOM elements using many array and Ajax declarations too.
Every Ajax object or class should be simple or really complex and some browser should declare it faster or slower than other one.
Another generic relevant thing is code optimizzation ... you could use "only Opera" to surf the web but if a library contains bad practices its code execution will be slow in every case.
And again, the use of "var" before every temporary variable should be slower or faster, look at the MathEngine function ... is this usefull ?
is this a real application example ?
The StringFuncs has 2 operations that are only for human eyes because if you don't call those functions how can you test them ?
str.toLowerCase; // yeah! a string has a toLowerCase prototype ..
str.toUpperCase; // yeah! a string has a toUpperCase prototype ..
// P.S. I think that He's just forgot it :)
A "StringBuilder" function should be a better test too because every JS developer knows that using string += something isn't a good speed practice and the use of concat instead of '+''+''+''+''+' ... is faster too.
A StringBuilder operation is not different from array.push, but doesn't use sort and reverse as ArrayFuncs does.
Is a StringBuilred competition another usefull test to do ? I think that ...
function StringBuilder() {
function StringBuilder() {
this.append = function(what){
arr.push(what);
};
this.toString = function(){
return arr.join("");
};
var arr = [""];
};
var startTime = getTime(), i = 4001, sb = new StringBuilder;
while(i--)
sb.append("a piece of code".concat(i));
sb = sb.toString();
var endTime = getTime();
getElement('speed_sb').innerHTML = (endTime - startTime);
getElement('speed_total').innerHTML = eval(getElement('speed_total').innerHTML) + (endTime - startTime);
};
... and Should we care about few milliseconds ?
Then this is what I think: these speed tests are a must only for Rhino or SpiderMonkey developers because a javascript developer doesn't need to care about performances (in this way) ... He needs to care about generic code optimizzations using lightweight code implementations without redundant operations inside a cross-browser code.
That's what a developer should care about, not dedicated speed test for this or that function.
Finally, this is a revisited version of that benchmark, enjoy with it, don't care about it!
See you :)
Sunday, September 24, 2006
a better DOMContentLoaded ?
a better DOMContentLoaded ?
The first line of this post is dedicated to Dean Edwards: thank you very much for your DOMContentLoaded implementation !!!
Without Dean solution I'll probably never create the code I'm going to show, than thanks again Dean.
Next step is my solution code concept:
if we need to write runtime a script tag, why should we use conditional comments if we could implement the solution directly with that tag for other browsers too ?
Since onreadystatechange inside a script tag is called only from IE and Safari, we could write this properties directly inside the script tag, then we don't need any anonimous function and we don't need any webkit dedicated interval too.
If we write a javascript source using void(0) as undefined source we could use undefined source using a function with an undefined return.
Then if we need to use defer with uncompatible browsers, we could set its value as generic value (I think it's more clean and elegant) and if we use our functions with the script we don't need to get it then we don't need it's id too.
This code is the base for my onContent callback, that's based on a single global object, used fromthe tag to call functions.
It's time to show my lightweight function (less than 500 bytes), compatible with FireFox, Opera 9, IE5+ and Safari (thank you guidoz) and compatible with other browsers too (IE4, Opera < 9, others), using "old" window.onload method.
Let me explain what this function does :)
__onload__ is the global object used by script tag and has 2 methods and just 1 parameter.
The dollar method $ is a shortcut to delete window.onload callback with every "DOMContentLoaded" compatible browser and then $ calls the callback too.
The second function, called IES, is the IE/Safari dedicated callback, used inside onreadystatechange event.
This function recieves the this (window) object and then check if its readyState is "complete", then call the dollar $ function to delete onload and to call callback.
The last FO parameter is dedicated to FireFox and Opera but preserve javascript errors using addEventListener only if this document method is available.
In other cases, this parameter will be the string "void(0)".
We don't need to care about addEventListener compatible browsers (i.e. Safari) because if they don't support the "DOMContentLoaded" event they'll necer use that listener.
FireFox as Opera will use that method directly (onerror, for FireFox, and onload, for Opera, script functions have a delay and if you add DOMContentLoaded event after page is loaded (cached) this will nevver be called).
Next line is the window.onload method, used from every browser ... then if __onload__ "hack" fails, callback will be called without problems.
The next line contains an if, this is necessay for Opera version older than 9 because Opera 8.5, for example, doesn't show the page if you write a script tag while page is downloading.
Final line writes the script tag, adding event or void inside src, adding defer="defer" for IE and setting onreadystatechange for IE and Safari.
What about addLoadEvent for multiple onload callbacks ?
I think that a single callback, if we don't use external libraries, is sufficient to call every other event on page complete or on dom ready (just calling multiple functions inside another one).
However this should be a simple solution to add multiple events using onContent function.
First line calls onContent if __onload__ object doesn't exists then creates the __onload__ object too and add a callback to call an __onload__ method.
callEvents is this one and it's used on page complete.
It loops over every callback and calls them.
Last if/else creates the __onload__.events array, adding first callback too.
Finally You could create a single function moving onContent inside addContentEvent (at the top), if addContentEvent is your favourite way to add callbacks.
The last thing ? The Example Page, where you should read event: onContent with compatible browsers (and please let me know if some browser is no compatible).
P.S. this blog doesn't require an account to reply ;)
UPDATE
For some reason Safari (at least some versionof Safari) doesn't accept an undefined source script and shows an error when this function write the script tag.
To solve this problem I've changed the function that now has the same snif used by Dean Edwards plus Konqueror snif (for KDE 3.X).
This is my updated solution, now tested with a real big range of browsers with a size of 650 bytes.
The first line of this post is dedicated to Dean Edwards: thank you very much for your DOMContentLoaded implementation !!!
Without Dean solution I'll probably never create the code I'm going to show, than thanks again Dean.
Next step is my solution code concept:
if we need to write runtime a script tag, why should we use conditional comments if we could implement the solution directly with that tag for other browsers too ?
Since onreadystatechange inside a script tag is called only from IE and Safari, we could write this properties directly inside the script tag, then we don't need any anonimous function and we don't need any webkit dedicated interval too.
<script id=__ie_onload defer src=javascript:void(0) onreadystatechange=ourFunction><\/script>
If we write a javascript source using void(0) as undefined source we could use undefined source using a function with an undefined return.
<script id=__ie_onload defer src=javascript:ourFunction2() onreadystatechange=ourFunction><\/script>
Then if we need to use defer with uncompatible browsers, we could set its value as generic value (I think it's more clean and elegant) and if we use our functions with the script we don't need to get it then we don't need it's id too.
<script src="javascript:ourFunction2()" defer="defer" onreadystatechange="ourFunction()"><\/script>
This code is the base for my onContent callback, that's based on a single global object, used fromthe tag to call functions.
It's time to show my lightweight function (less than 500 bytes), compatible with FireFox, Opera 9, IE5+ and Safari (thank you guidoz) and compatible with other browsers too (IE4, Opera < 9, others), using "old" window.onload method.
function onContent(callback){
__onload__={
$:function(){window.onload=null;callback()},
IES:function(e){if(e.readyState==="complete")this.$()},
FO:document.addEventListener?"document.addEventListener('DOMContentLoaded',__onload__.$,false)":"void(0)"
};
onload=callback;
if(!window.opera||parseInt(window.opera.version())>=9)
document.write(''));
};
Let me explain what this function does :)
__onload__ is the global object used by script tag and has 2 methods and just 1 parameter.
The dollar method $ is a shortcut to delete window.onload callback with every "DOMContentLoaded" compatible browser and then $ calls the callback too.
The second function, called IES, is the IE/Safari dedicated callback, used inside onreadystatechange event.
This function recieves the this (window) object and then check if its readyState is "complete", then call the dollar $ function to delete onload and to call callback.
The last FO parameter is dedicated to FireFox and Opera but preserve javascript errors using addEventListener only if this document method is available.
In other cases, this parameter will be the string "void(0)".
We don't need to care about addEventListener compatible browsers (i.e. Safari) because if they don't support the "DOMContentLoaded" event they'll necer use that listener.
FireFox as Opera will use that method directly (onerror, for FireFox, and onload, for Opera, script functions have a delay and if you add DOMContentLoaded event after page is loaded (cached) this will nevver be called).
Next line is the window.onload method, used from every browser ... then if __onload__ "hack" fails, callback will be called without problems.
The next line contains an if, this is necessay for Opera version older than 9 because Opera 8.5, for example, doesn't show the page if you write a script tag while page is downloading.
Final line writes the script tag, adding event or void inside src, adding defer="defer" for IE and setting onreadystatechange for IE and Safari.
What about addLoadEvent for multiple onload callbacks ?
I think that a single callback, if we don't use external libraries, is sufficient to call every other event on page complete or on dom ready (just calling multiple functions inside another one).
However this should be a simple solution to add multiple events using onContent function.
function addContentEvent(callback) {
if(!window.__onload__)
onContent(function(){__onload__.callEvents()});
__onload__.callEvents = function() {
for(var i = 0; i < __onload__.events.length; i++)
__onload__.events[i]();
};
if(!__onload__.events)
__onload__.events = [callback];
else
__onload__.events[__onload__.events.length] = callback;
};
// Example:
// addContentEvent(function(){alert("hello dom 1")});
// addContentEvent(function(){alert("hello dom 2")});
First line calls onContent if __onload__ object doesn't exists then creates the __onload__ object too and add a callback to call an __onload__ method.
callEvents is this one and it's used on page complete.
It loops over every callback and calls them.
Last if/else creates the __onload__.events array, adding first callback too.
Finally You could create a single function moving onContent inside addContentEvent (at the top), if addContentEvent is your favourite way to add callbacks.
The last thing ? The Example Page, where you should read event: onContent with compatible browsers (and please let me know if some browser is no compatible).
P.S. this blog doesn't require an account to reply ;)
UPDATE
For some reason Safari (at least some versionof Safari) doesn't accept an undefined source script and shows an error when this function write the script tag.
To solve this problem I've changed the function that now has the same snif used by Dean Edwards plus Konqueror snif (for KDE 3.X).
This is my updated solution, now tested with a real big range of browsers with a size of 650 bytes.
function onContent(callback){
__onload__={
E:function(){window.onload=null;callback()},
IES:function(e){if(e.readyState==="complete")this.E()},
FO:document.addEventListener?"document.addEventListener('DOMContentLoaded',__onload__.E,false)":"void(0)"
};
onload=callback;
if(/WebKit|Konqueror/i.test(navigator.userAgent))
(function(){/loaded|complete/.test(document.readyState)?__onload__.E():setTimeout(arguments.callee,1)})();
else if(!window.opera||parseInt(window.opera.version())>=9)
document.write('');
};
Friday, September 22, 2006
F.A.P. - Fast Archive Preview
What is F.A.P. ???
F.A.P. is my archive preview idea, a fast way to know a title and its permanent link of each post and for each month (or date).
You can view an example scrolling this page to Archieves and wait few seconds over one month just with your mouse.
How does F.A.P. work ?
Blogspot is a wonderfull and free service but its server is not available to its users.
There's no way (at least I've not found anyone) to implement ajax request to do some "experiment".
However, we are really lucky because blogspot doesn't block external requests, then every host should read our blog content, simply calling one page.
This was the key to create F.A.P. web service, that's a simple dedicated blogspot output parser.
The called external page will read a built archive page, for example one of the pages you can find under the Archieves on your left or right side of your blog.
After that our external requet page will produce a JSON like output usable for our scripts.
How to implement F.A.P. in your blogspot place ?
The first thing to do is a class or a function that can add dinamically a javascript tag inside page's head tag.
I've used this simple Class to do that
This class has only 3 public methods
- add, to add one or more external javascript file
- clear, to clear every external javascript file we have add
- remove, to remove one or more external javascript file from pur head
The second thing to do is to create a global variable to save (or cache) requet informations.
The name of this var is, obviously, webreflection :D
Now we need to add an onload event because we need to find and modify every Archive Link.
I'm sorry for my bad english and I hope you've understund what this script does.
There's just a final function to view, the monthPreview function.
Last thing to know is that you can modify your "preview div" layout using css inside your blogspot page model.
To have the web service You can use my space but please, when I'll tell you (give me few days) what does server side script do to create response, use your server not mine :D
Finally, it's the complete script without comments, see you.
F.A.P. is my archive preview idea, a fast way to know a title and its permanent link of each post and for each month (or date).
You can view an example scrolling this page to Archieves and wait few seconds over one month just with your mouse.
How does F.A.P. work ?
Blogspot is a wonderfull and free service but its server is not available to its users.
There's no way (at least I've not found anyone) to implement ajax request to do some "experiment".
However, we are really lucky because blogspot doesn't block external requests, then every host should read our blog content, simply calling one page.
This was the key to create F.A.P. web service, that's a simple dedicated blogspot output parser.
The called external page will read a built archive page, for example one of the pages you can find under the Archieves on your left or right side of your blog.
After that our external requet page will produce a JSON like output usable for our scripts.
How to implement F.A.P. in your blogspot place ?
The first thing to do is a class or a function that can add dinamically a javascript tag inside page's head tag.
I've used this simple Class to do that
function DinamycScriptInclusion() {
// (C) Andrea Giammarchi - MIT Style Licence - webreflection.blogspot.it
function __add(fileName) {
var js = document.createElement('script');
js.language = "javascript";
js.type = "text/javascript";
js.src = fileName;
__fileList.push(fileName);
document.getElementsByTagName('head').item(0).appendChild(js);
};
function __remove(fileName, i) {
var scripts = document.getElementsByTagName('script'),
j = scripts.length;
while(j--) {
if(scripts.item(j).src == fileName)
scripts.item(j).parentNode.removeChild(scripts.item(j));
};
__fileList[i] = null;
};
this.add = function() {
for(var i = 0, j = arguments.length; i $lt; j; i++) {
if(__fileList.indexOf(arguments[i]) !== -1)
this.remove(arguments[i]);
__add(arguments[i]);
}
};
this.clear = function() {
__fileList.forEach(function(fileName, i){__remove(fileName, i)});
__fileList = [];
};
this.remove = function() {
for(var i = 0, j = arguments.length; i $lt; j; i++) {
if(__fileList.indexOf(arguments[i]) !== -1)
__remove(arguments[i], i);
__fileList = __fileList.filter(function(e){return e !== null});
}
};
var __fileList = [];
};
This class has only 3 public methods
- add, to add one or more external javascript file
- clear, to clear every external javascript file we have add
- remove, to remove one or more external javascript file from pur head
The second thing to do is to create a global variable to save (or cache) requet informations.
The name of this var is, obviously, webreflection :D
webreflection = {};
Now we need to add an onload event because we need to find and modify every Archive Link.
// use your favourite "addEvent" method, this is only an example
onload = function() {
var blogName = "your_blog_name_here", // i.e. blogName = "webreflection"
li = document.getElementsByTagName("LI"),
i = li.length,
link = null,
tmp = blogName.replace(/-/g, "\\-"),
re = new RegExp("(http://".concat(tmp, "\\.blogspot\\.com/)([\\w]+)(_", tmp, "_archive\\.html)"));
// loop over every found LI
while(i) {
// blogspot calls UL Archive container class "archive-list"
// we're interesting only to this container, that should be
// the parent node of one or more LI
if(li[--i].parentNode.className === "archive-list") {
// well, we have found an Archive li
// then we can add a div (unobtrusive layout)
// that will be used with F.A.P.
li[i].innerHTML += "");
// we can use a class name, then in our CSS div.month-ghost can be as you want
// now we need to get the link inside this LI
link = li[i].childNodes[0];
// and we need to get date inside this link
// stored inside the link as an un-standard parameter
link.webreflection_remstring = link.href.replace(re, "$2");
// we need to save created div too, using unique id created with innerHTML
link.webreflection_div = document.getElementById("month-ghost-".concat(i));
// we must hide created div (then you don't need to write display: none inside CSS)
link.webreflection_div.style.display = "none";
// and we must set link referer too (this.referer shortcut)
link.webreflection_div.referer = link;
// we need to add events to link and to div too to manage F.A.P.
// link onmouseover
link.onmouseover = function() {
// usefull callback
function loaded() {
// if external host has created output
if(webreflection.response) {
// delete the interval
clearInterval(element.webreflection_interval);
// and call monthPreview function
monthPreview(element);
}
};
// element is this link scope inside this function (and loaded function too)
// txt is the date inside the url of this link
// url is the page to call with your blog name and the date as query string
var element = this,
txt = this.webreflection_remstring,
url = "http://win.3site.eu/fap.aspx?blogname=".concat(blogName, "&date=", txt);
// if there's an interval (created by onmouseout)
if(element.webreflection_interval)
clearInterval(element.webreflection_interval);
// if webreflection_div_content parameter is present, we don't need to call external page
// then just show old result
if(element.webreflection_div_content)
monthPreview(element);
else {
// reset old webreflection.response
webreflection.response = null;
// clear old scripts add on head tag
DSI.clear();
// and add created url
DSI.add(url);
// then set the interval to check webreflection.response
element.webreflection_interval = setInterval(loaded, 20);
}
};
// link onmouse out
link.onmouseout = function() {
// function to hide the div
function removeDiv() {
element.webreflection_div.style.display = "none";
};
// element is the this scope for the function (for removeDiv too)
var element = this;
// if onmouseover hasn't load the content, the interval is not 0 (not false)
if(element.webreflection_interval)
// then stop that interval
clearInterval(element.webreflection_interval);
// and call after 500 seconds remove function
element.webreflection_interval = setInterval(removeDiv, 500);
};
// div onmouse over
link.webreflection_div.onmouseover = function() {
// while we go with mouse over the div the link will create an interval
// (onmouseout) to remove this div after 1/2 second ... then stop them
clearInterval(this.referer.webreflection_interval);
};
// div onmouseout over
link.webreflection_div.onmouseout = function() {
// when we leave the div we want to call link onmouseout to hide them
this.referer.onmouseout();
};
}
};
};
I'm sorry for my bad english and I hope you've understund what this script does.
There's just a final function to view, the monthPreview function.
// function to write the content inside the div
function monthPreview(element) {
// div was saved as link.webreflection_div
// content is an array used "as StringBuild" to add content
var div = element.webreflection_div,
content = [];
// if content was loaded
if(element.webreflection_div_content)
// add that
div.innerHTML = element.webreflection_div_content;
// else create the output with webreflection.response array
else {
for(var i = 0, e = webreflection.response; i $lt; e.length; i++)
content.push('<a href="'.concat(e[i].link,'">',e[i].title,'</a>'));
};
// now we can show the div
div.style.display = "";
// and cache its content for next time :)
element.webreflection_div_content = div.innerHTML;
};
Last thing to know is that you can modify your "preview div" layout using css inside your blogspot page model.
To have the web service You can use my space but please, when I'll tell you (give me few days) what does server side script do to create response, use your server not mine :D
Finally, it's the complete script without comments, see you.
Thursday, September 21, 2006
JavaScript benchmark for while and for loop
It's just a page to test directly differents loops and respective times with blue "winners" too :)
If you have a really old (or slow) PC please don't visit the page.
If you visit the page and everything stops, close the page and wait few seconds.
Loops Benchmark: http://www.devpro.it/examples/loopsbench/
If you have a really old (or slow) PC please don't visit the page.
If you visit the page and everything stops, close the page and wait few seconds.
Loops Benchmark: http://www.devpro.it/examples/loopsbench/
Wednesday, September 20, 2006
anonymous function to add simple events
This post shows as is possible to set prototypes with anonymous functions.
This one shows a simple anonymous function application example, a fake addEventListener.
We often use directly the method with the document element, it's simple and fast, then often our preferred way to implement an event.
I'm talking about this code
DOM and standars like this method to add an event
But IE doesn't implement addEventListener method (what a news ...)
The attachEvent has different problems, it isn't a standard method (then IE and few other browsers supports that) and the scope inside the callback is not the element.
This code, for example, doesn't work as expected:
I've implemented the addEventListener in my big dollar function but often developers doesn't like "big" external libraries (scriptacolous as prototype and Dojo are some exceptions).
That's why I'm writing this simple function to add an event directly to an element, using generic on* event names.
This function uses anonymous function to preserve old event (base variable), if presents, and calls every callback with the element scope (using call).
This is an example:
Just test this script to view this sequence of alerts
Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
Hello 6
What's about compatibility ? Every browser that supports call and doesn't loose base variable during execution, then IE 5.5+, FireFox, Opera, KDE, Safari and many others.
I hope this little function will be usefull for you window, document, or element common events.
This one shows a simple anonymous function application example, a fake addEventListener.
We often use directly the method with the document element, it's simple and fast, then often our preferred way to implement an event.
I'm talking about this code
document.getElementById("myId").onclick =
function(){alert("hello")};
DOM and standars like this method to add an event
document.getElementById("myId").addEventListener(
"click",
function(){alert("hello")},
false
);
But IE doesn't implement addEventListener method (what a news ...)
document.getElementById("myId").attachEvent(
"onclick",
function(){alert("hello")}
);
The attachEvent has different problems, it isn't a standard method (then IE and few other browsers supports that) and the scope inside the callback is not the element.
This code, for example, doesn't work as expected:
document.getElementById("myId").attachEvent(
"onclick",
function(){alert(this.className)}
);
I've implemented the addEventListener in my big dollar function but often developers doesn't like "big" external libraries (scriptacolous as prototype and Dojo are some exceptions).
That's why I'm writing this simple function to add an event directly to an element, using generic on* event names.
function addSimpleEvent(
obj, // the object (i.e. window, document, element)
type, // the type (i.e. "onload", "onmouseover", "onclick")
callback // the callback (i.e. function(){alert(this)})
) {
obj[type] = (function(base){ // anonymous function
return function(evt){ // function called on event
if(!evt)evt=window.event; // event for IE browsers
if(base)base.call(this,evt); // old function, if defined
callback.call(this,evt); // callback
}
})(obj[type]) // old defined (or not) function
};
This function uses anonymous function to preserve old event (base variable), if presents, and calls every callback with the element scope (using call).
This is an example:
// imagine that other script did it ...
onload = function(){alert("Hello 1")};
// addSimpleEvent function
function addSimpleEvent(obj,type,callback) {
obj[type] = (function(base){return function(evt){
if(!evt)evt=window.event;
if(base)base.call(this,evt);
callback.call(this,evt);
}})(obj[type])
};
// you can add one, two or more events
addSimpleEvent(window, "onload", function(){alert("Hello 2")});
addSimpleEvent(window, "onload", function(){alert("Hello 3")});
// if you want, you could create another function to add multiple events of same type
function addMultipleEvents() {
for(var i = 2, j = arguments.length; i < j; i++)
addSimpleEvent(arguments[0], arguments[1], arguments[i]);
}
// and use it in this way
addMultipleEvents(window, "onload",
function(){alert("Hello 4")},
function(){alert("Hello 5")},
function(){alert("Hello 6")}
);
Just test this script to view this sequence of alerts
Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
Hello 6
What's about compatibility ? Every browser that supports call and doesn't loose base variable during execution, then IE 5.5+, FireFox, Opera, KDE, Safari and many others.
I hope this little function will be usefull for you window, document, or element common events.
anonymous function prototype
There are several scripts that use anonymous functions and we often use them as regulars.
Is there a way to have different or dedicated prototypes for this kind of function ?
Step 1, what is anonymous function ?
The "original" anonymous function is returned from the global Function object.
myFunc is a function with all Function prototypes or native methods and with the same constructor of a function.
Then myFunc is absolutely a function, but wich kind of function is it ? Exactly this one:
What's that ? That's a function that exists but you can't modify, get, or extend anyway because each new Function will produce a different referer for a different anonymous function.
You can try in a different ways creating for example a personal anonymous function, but the result will be the same ...
That's becaus, as I've just said, every anonymous instance is different from every other.
With FireFox you should view this difference using toSource Obect native method.
As you can see, those parentheses are the key to understand the anonymous function.
Step 2, parentheses and virtual scope
At this point we know that an anonymous functions cannot have dedicated prototypes and aren't like regular functions too.
In some script you can see the use of parentheses to call runtime a function or to create one.
This code, for example, is an unobtrusive way to add a personal String prototype.
Let me explain this few lines of code.
If some script, before this one, has just defined a String.prototype.toArray or browser has a native String.toArray function, the anonymous function created using parentheses and directly called with (String.prototype.toArray) that accepts, if present, the base function, will assign to that prototype old version (base) or, if base is not defind, our prototype function (function(){return this.split("")}).
The closed anonymous function is then a special function and its really usefull to solve a lot of problems.
This is only a little example but I think you used anonymous functions every day with every scripts ;)
Since the scope inside parentheses "magically disappear", but neither for itsself nor for its internal scope, we can think that those kind of functions are exactly anonymous.
Step 3, how to create a dedicate prototype
JavaScript is Object Oriented and each function is an object, then why I couldn't use "special" anonymous functions as an object ?
That's why I've created a simple solution to have customizable anonymous functions, every one will be different from every other, but everyone will have our dedicate prototypes.
This is the concept function
The major difference from native new Function(arguments) is that my anonymous function accpets an anonymous function too.
Here there's a complete test to view some application.
Just a look at the last test, where is used arguments.callee instead of "this".
That's simply why the "this doesn't exists" inside the function ("this" inside a function is the window object).
That's all :)
Is there a way to have different or dedicated prototypes for this kind of function ?
Step 1, what is anonymous function ?
The "original" anonymous function is returned from the global Function object.
var myFunc = new Function("a", "b", "c", "return a + b + c;");
alert(myFunc(1,2,3)); // number 6
myFunc is a function with all Function prototypes or native methods and with the same constructor of a function.
Then myFunc is absolutely a function, but wich kind of function is it ? Exactly this one:
function anonymous(a, b, c) {
return a + b + c;
}
What's that ? That's a function that exists but you can't modify, get, or extend anyway because each new Function will produce a different referer for a different anonymous function.
(new Function).prototype.isAnonymous = true;
alert((new Function).isAnonymous); // undefined
You can try in a different ways creating for example a personal anonymous function, but the result will be the same ...
var anonymous = new Function;
(new Function).prototype.isAnonymous = true;
alert((new Function).isAnonymous); // undefined
// other way
function anonymous(){};
anonymous.prototype.isAnonymous = true;
alert((new Function).isAnonymous); // undefined
That's becaus, as I've just said, every anonymous instance is different from every other.
With FireFox you should view this difference using toSource Obect native method.
function anonymous(){};
var realanonymous = new Function;
alert([
anonymous.toSource(), // function anonymous() {}
realanonymous.toSource(), // (function anonymous() {})
anonymous === realanonymous // false
]);
As you can see, those parentheses are the key to understand the anonymous function.
Step 2, parentheses and virtual scope
At this point we know that an anonymous functions cannot have dedicated prototypes and aren't like regular functions too.
In some script you can see the use of parentheses to call runtime a function or to create one.
This code, for example, is an unobtrusive way to add a personal String prototype.
String.prototype.toArray = (function(base){
return base || function(){return this.split("")}
})(String.prototype.toArray);
alert("test".toArray()); // t,e,s,t
Let me explain this few lines of code.
If some script, before this one, has just defined a String.prototype.toArray or browser has a native String.toArray function, the anonymous function created using parentheses and directly called with (String.prototype.toArray) that accepts, if present, the base function, will assign to that prototype old version (base) or, if base is not defind, our prototype function (function(){return this.split("")}).
The closed anonymous function is then a special function and its really usefull to solve a lot of problems.
This is only a little example but I think you used anonymous functions every day with every scripts ;)
Since the scope inside parentheses "magically disappear", but neither for itsself nor for its internal scope, we can think that those kind of functions are exactly anonymous.
var myAnonymous = (function anonymous(){}),
realAnonymous = (new Function);
alert([
myAnonymous, // (function anonymous(){})
realAnonymous, // (function anonymous(){})
myAnonymous === realAnonymous, // false
myAnonymous.toSource() === realAnonymous.toSource()
// true !!!
]);
Step 3, how to create a dedicate prototype
JavaScript is Object Oriented and each function is an object, then why I couldn't use "special" anonymous functions as an object ?
That's why I've created a simple solution to have customizable anonymous functions, every one will be different from every other, but everyone will have our dedicate prototypes.
This is the concept function
// anonymous explicit function
function anonymous() {
// prototype to prototype,
// this function copy each a prototype (p) to other (b) function
function p2p(p,a,b) {
// using prototype for b too isn't a good solution (imho)
// because only new anonymous will has these prototypes
for(var k in a[p])b[k] = a[p][k];
return b;
};
// we need arguments and its length plus a genric array
var l = arguments.length, a = [];
// if argument is not one or its not a function
if(l !== 1 || arguments[0].constructor !== Function) {
// create the string ([arguments[N],...,arguments[0]])
while(l)a.push("arguments[".concat(--l,"]"));
// then reverse ...
a.reverse();
// ... to assign anonymous function to arguments 0
eval("arguments[0]=new Function(".concat(a.join(","),")"));
}
// return its "prototyped" version of anonymous function
return p2p("prototype", arguments.callee, arguments[0]);
};
The major difference from native new Function(arguments) is that my anonymous function accpets an anonymous function too.
Here there's a complete test to view some application.
// anonymous explicit function
function anonymous() {
function p2p(p,a,b) {
for(var k in a[p])b[k] = a[p][k];
return b;
};
var l = arguments.length, a = [];
if(l !== 1 || arguments[0].constructor !== Function) {
while(l)a.push("arguments[".concat(--l,"]"));
a.reverse();
eval("arguments[0]=new Function(".concat(a.join(","),")"));
}
return p2p("prototype", arguments.callee, arguments[0]);
};
// common Function prototype
Function.prototype.isFunction = true;
// only anonymous prototype
anonymous.prototype.isAnonymous = true;
// first test --------------------------------------
// new anonymous creation with the same sintax of new Function
test = anonymous("str", "alert(str)");
// just few checks
alert([
"" + anonymous.isAnonymous, // undefined, anonymous is a function
"" + test.isFunction, // true, test is a function
"" + test.isAnonymous // true, test is an anonymous function
]);
test("Hello World!"); // Hello World! [then test works perfectly]
// _________________________________________________
// second test --------------------------------------
// common function declaration using anonymous
test = anonymous(function(str){alert(str.toUpperCase())});
// just check it
alert([
"" + test.isFunction, // true, test is a function
"" + test.isAnonymous // true, test is an anonymous function
]);
test("Hello World!"); // HELLO WORLD! [then test works perfectly]
// _________________________________________________
// third test --------------------------------------
alert(anonymous(function(){}).isAnonymous); // true
// _________________________________________________
// final test --------------------------------------
anonymous(function(a){alert(a + arguments.callee.isAnonymous)})("Anonymous ? ");
// true
// _________________________________________________
Just a look at the last test, where is used arguments.callee instead of "this".
That's simply why the "this doesn't exists" inside the function ("this" inside a function is the window object).
That's all :)
Tuesday, September 19, 2006
studying google adsense code ...
PLEASE READ ME FIRST
This post is "a joke", then I hope you'll look at this as an ironical and hilarious post about google scripts and google developers that are really more skilled than me :)
I've found an error on my "best" script then I've looked for problem inside adsense code because with its code my script generates strange redirect errors (adsense code escapes objects or numbers too without string casting while my encodeURIComponent implementation didn't care about toString() method befor parsing ... I know, I've done a stupid thing :P )
studying code ...
3 days ago I've posted about an unknown problem using my JSL at the top of this blog.
The first point is ... sorry blogspot, you didn't cause any problem to JSL
The secondo point is this one: google adsense ... have you seen the code ?
To find the problem and then the solution I've downloaded adsense code to look inside that after a "manual code beautifier operation".
That's what I think about adsense code:
Let's analyze adsense JS code, using this page as referer: google adsense beautified code.
The good thing is that all adsense code is inside an anonymous function, then every other script on the page will not be modified ... every but another google adsense script, because the use of window inside the script allows itself to create a big list of window.google_* variables.
This shouldn't be a problem, but if you use a script that does a for in loop with the window oblect, you need to rememeber that every /^google_/.test(param) should be leave as is.
It's time to view the internal function code, starting from optimizzations.
As you can read on many lines, for example on line 6, every if / else if / else uses curly brackets ... even when it's not necessary (every single operation after the condition).
But if you look at the line 295, someone uses correctly an "if" without braces ... who did this ? Maybe not the same developer ?
Since it's correct even with single line funtions, to optimize this script a lot of braces should be removed, adding where we need a ";" char.
Then I've just removed 2 chars from the size of the script but hey ... that function should be different!
Another example is on line 153, where there is a ternary operation for var h but not for var q.
After few lines (159) we can read another "unoptimized" piece of code that should be wrote in one line.
However I wonder when this piece of code should be usefull because google_num_0ad_slots is not present in this script, then it's maybe defined from other scripts.
If this is true or not, the if,else and then if does something like this:
if google_num_0ad_slots is not defined, or is null or is 0, google_num_0ad_slots should be 1, in every other case should be google_num_0ad_slots + 1 then it should be 0 if google_num_0ad_slots is less than zero.
These "if/else and then if again" I've just optimized are in different lines of the script but in some cases there is only an if else (i.e. 170 whre there's any "greater than 1" check)
In these cases the code should be
or should be this one
only if parameter is always initialized with 0 or greater value.
Another little optimizzation should be done on function F (line 73).
Since adsense code optimizzation is based on short var names I think that repeat for a lot of times the same object param prefix is not so good as a dedicated params array should be:
In this way all properties are simple to add or to remove from the list, and "b.google_" is present just one time.
However if an optimized while should be slower to parse with a really big array, using o.param1=o.param2=o.paramN=null instead of "=a" for each param should be the same thing.
AdSense script uses a lot of returns in-function, that is a method I don't like very much (but it's only my opinion and using only one return isn't a better way to write functions).
For example there's a "special" function I've seen that's not good enought for me, it is the x function (line 293).
If you look at the original version you can view that if z is true (then r in my version), function returns false.
Then if !r (when r is not true) it's possibile to do other operations inside the first if condition.
At the end of the first if you can assign a boolean value without the if and the second in-function return.
Then if r is true, the final return value is false. It's true for the first check as for the second, then in every other cases, when r is not true, returned value will be true (not false).
This is the way I usually like to return a boolean value from a function or method using only a single return (cleaner, imho) at the end of the function.
We are going to the end of this post, there's only another function I've not understand ... the C function (line 286).
As you can see C function recieves 3 parameters, any of these is used, A function is called and true value is returned.
Do you think it's usefull ? I think that A function, that doesn't have any input parameters and doesn't return anything, should return true value and should be used directly on line 325.
... adding return true on A function ... then anyone doesn't need the C function (but maybe it was created for future implementations).
The absolute last thing I want to tell to google AdSense script developers is this one:
why do you optimize in this way the code but you use "var" for every temporary function variable ?
Look at the line 319, inside the function E ... wasn't better something like ...
??? it's the same with A, D and other functions ...
This post is "a joke", then I hope you'll look at this as an ironical and hilarious post about google scripts and google developers that are really more skilled than me :)
I've found an error on my "best" script then I've looked for problem inside adsense code because with its code my script generates strange redirect errors (adsense code escapes objects or numbers too without string casting while my encodeURIComponent implementation didn't care about toString() method befor parsing ... I know, I've done a stupid thing :P )
studying code ...
3 days ago I've posted about an unknown problem using my JSL at the top of this blog.
The first point is ... sorry blogspot, you didn't cause any problem to JSL
The secondo point is this one: google adsense ... have you seen the code ?
To find the problem and then the solution I've downloaded adsense code to look inside that after a "manual code beautifier operation".
That's what I think about adsense code:
- absolutely "undebuggable", to be lightweight (about 7Kb in a local file, maybe compressed on-line with gz, then 2Kb) variables and function names are really hard to understand
- contains few errors, Opera as FireFox show everytime something inside the js console
- it doesn't use a "perfectly" optimized code
Let's analyze adsense JS code, using this page as referer: google adsense beautified code.
The good thing is that all adsense code is inside an anonymous function, then every other script on the page will not be modified ... every but another google adsense script, because the use of window inside the script allows itself to create a big list of window.google_* variables.
This shouldn't be a problem, but if you use a script that does a for in loop with the window oblect, you need to rememeber that every /^google_/.test(param) should be leave as is.
It's time to view the internal function code, starting from optimizzations.
As you can read on many lines, for example on line 6, every if / else if / else uses curly brackets ... even when it's not necessary (every single operation after the condition).
But if you look at the line 295, someone uses correctly an "if" without braces ... who did this ? Maybe not the same developer ?
Since it's correct even with single line funtions, to optimize this script a lot of braces should be removed, adding where we need a ";" char.
// example with function B (starting from line 5)
function B(b){
if(typeof encodeURIComponent=="function")
return encodeURIComponent(b);
else
return escape(b);
}
Then I've just removed 2 chars from the size of the script but hey ... that function should be different!
// another example with function B
function B(b){
return typeof encodeURIComponent=="function"?encodeURIComponent(b):escape(b)
}
Another example is on line 153, where there is a ternary operation for var h but not for var q.
var h=a.google_ad_region==b?"":a.google_ad_region,q=j?j.indexOf("_0ads")>0:false;
After few lines (159) we can read another "unoptimized" piece of code that should be wrote in one line.
a.google_num_0ad_slots=!a.google_num_0ad_slots||a.google_num_0ad_slots+1>1?1:a.google_num_0ad_slots+1;
However I wonder when this piece of code should be usefull because google_num_0ad_slots is not present in this script, then it's maybe defined from other scripts.
If this is true or not, the if,else and then if does something like this:
if google_num_0ad_slots is not defined, or is null or is 0, google_num_0ad_slots should be 1, in every other case should be google_num_0ad_slots + 1 then it should be 0 if google_num_0ad_slots is less than zero.
if(!a.google_num_0ad_slots||++a.google_num_0ad_slots>1)a.google_num_0ad_slots=1;
These "if/else and then if again" I've just optimized are in different lines of the script but in some cases there is only an if else (i.e. 170 whre there's any "greater than 1" check)
In these cases the code should be
if(!a.google_num_ad_slots)a.google_num_ad_slots=0;
++a.google_num_0ad_slots;
or should be this one
if(!++a.google_num_ad_slots)a.google_num_ad_slots=1;
only if parameter is always initialized with 0 or greater value.
Another little optimizzation should be done on function F (line 73).
Since adsense code optimizzation is based on short var names I think that repeat for a lot of times the same object param prefix is not so good as a dedicated params array should be:
function F(b){
var a=[
"ad_frameborde","ad_format","page_url","language","gl","country","region","city","hints","safe",
"encoding","ad_output","max_num_ads","ad_channel","contents","alternate_ad_url","alternate_color",
"color_bg","color_text","color_link","color_url","color_border","color_line","adtest","kw_type",
"kw","num_radlinks","max_radlink_len","rl_filtering","rl_mode","rt","ad_type","image_size","feedback",
"skip","page_location","referrer_url","ad_region","ad_section","bid","cpa_choice","cust_age","cust_gender",
"cust_interests","cust_id","cust_job","cust_u_url"
],l=a.length;
while(l)b["google_"+a[--l]]=null;
}
In this way all properties are simple to add or to remove from the list, and "b.google_" is present just one time.
However if an optimized while should be slower to parse with a really big array, using o.param1=o.param2=o.paramN=null instead of "=a" for each param should be the same thing.
AdSense script uses a lot of returns in-function, that is a method I don't like very much (but it's only my opinion and using only one return isn't a better way to write functions).
For example there's a "special" function I've seen that's not good enought for me, it is the x function (line 293).
function x(b,a){
var d=a.documentElement,r=z(b,a,"location"),g=1,e=1;
if(!r&&b.google_ad_width&&b.google_ad_height){
if(b.innerHeight){
g=b.innerWidth;
e=b.innerHeight
}
else if(d&&d.clientHeight){
g=d.clientWidth;
e=d.clientHeight
}
else if(a.body){
g=a.body.clientWidth;
e=a.body.clientHeight
}
r=(e>2*b.google_ad_height||g>2*b.google_ad_width)
}
return !r
}
If you look at the original version you can view that if z is true (then r in my version), function returns false.
Then if !r (when r is not true) it's possibile to do other operations inside the first if condition.
At the end of the first if you can assign a boolean value without the if and the second in-function return.
Then if r is true, the final return value is false. It's true for the first check as for the second, then in every other cases, when r is not true, returned value will be true (not false).
This is the way I usually like to return a boolean value from a function or method using only a single return (cleaner, imho) at the end of the function.
We are going to the end of this post, there's only another function I've not understand ... the C function (line 286).
As you can see C function recieves 3 parameters, any of these is used, A function is called and true value is returned.
Do you think it's usefull ? I think that A function, that doesn't have any input parameters and doesn't return anything, should return true value and should be used directly on line 325.
b.onerror=A;
... adding return true on A function ... then anyone doesn't need the C function (but maybe it was created for future implementations).
The absolute last thing I want to tell to google AdSense script developers is this one:
why do you optimize in this way the code but you use "var" for every temporary function variable ?
Look at the line 319, inside the function E ... wasn't better something like ...
var b=window,a=document,d=a.location,g=a.referrer,e=null;
??? it's the same with A, D and other functions ...
Subscribe to:
Posts (Atom)