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

Friday, December 22, 2006

[PHP] New version of GzOutput class

I've just updated my recent GzOutput.class.php (more recent than last file published on Ajaxian :D) and tested successful on many browsers.

The difference from other cache-manager files, functions or classes is that GzOutput is totally indipendent from folders or page type, You could use them to increase JSON responses (using text/plain as Content-Type) as well as XML, (X)HTML, CSS or every kind of document You need.

You could combine this class with a JavaScript compressor (to improve download speed) and you don't need to care about output changes because ETag is based on sha1 and not on every mktime of each file (it means better server performances).

The only think that You need to remember is that You don't need to write everything before to use this class (empty spaces, some char or pages can't be write before its usage).

Four public methods are really simple to use:

create, sending an output string and a Content-Type type to use cache if it's available (if not, forces next download to use cache)

createNew, sending an output and a Content-Type to force everytime the download (it's a must for Ajax interactions with XML, JSON or serialized strings)

createFromList, sending an array of files and a Content-Type to create a single generic output file including each file content and using create properties for output

createNewFromList, sending an array of files and a Content-Type to create a single generic output file including each file content and using createNew properties for output

That's all, do You like it ? :-)

Wednesday, December 20, 2006

PHP API Manager for Notepad++

I've used fantastic Komodo IDE to develop for a lot of time my Python/PHP web/desktop applications but now that my portable PC "has been regenerated" from SONY I'm spendig a lot of time to re-install everything I need.

My first favourite editor was ConTEXT, a fantastic, fast and powerful editor for every kind of program language but "my last love" has been Komodo that I've won on phpclasses.org.

Difference is amazing but there's just a problem .... Komodo is too much powerful and wants a lot of resources (I've not an extremely powerful VAIO) then I've choosed to install ConTEXT one more time but I've found, inside a forum, another famous editor as Notepad++ is and I don't know why I didn't try them before.

It's exactly what I need, a fast, simple, scite based, auto-completition enabled editor, then it's fantastic because I can write PHP as JavaScript, C and many other languages too !!!

Auto-completition is just what ConTEXT doesn't have but hey, it's a must to remember perfectly each kind of function or method because You can use them with CTRL and SPACE where You want then php.api file, as javascript.api files are a perfect solution to develop quickly without an api search engine under your nose ;-)


That's why I've created two really stupid PHP files to manage PHP API, one to create a personal installation dedicated api and one to update and mantain an api with old, unused or deprecated method too.

This is the readme file:

PHP API Manager - Andrea Giammarchi [http://webreflection.blogspot.com/]

These two simple phpfiles overwrite or create php.api file for Notepad++ program [http://notepad-plus.sourceforge.net/]

Usage:

- notepad.dedicated.api.php

call this file to create your personal PHP configuration api.
This script create php.api file for Notepad++ program overwriting, if present, precedent php.api file version.
Use this application if You don't need other not loaded/present extensions of your php installation.


- notepad.update.api.php

call this file to update your personal PHP configuration api or original Notepad++ default php.api file.
This script create php.api file for Notepad++ program overwriting, if present, precedent php.api file version.
Use this application if You want every other php functions too that shouldn't be present on your php installation.
Please remember to copy old php.api file inside this folder before to launch this application.


And this is the link of downloadable zip file with these two php scripts (on title too).

Have fun with Notepad++ :-)

Firefox Multiple Vulnerabilities ? Update in few hours !

The Highly critical Secunia Advisory of 2006-12-19 is not a problem, FireFox 2.0.0.1 has been released in few hours !!!

You don't need to download this new version if you have auto update feature enabled because your FireFox will update by itself in a "couple of seconds".

I wonder when Microsoft Internet Explorer released an multiple patches update the day after after and then I wonder why You've not yet installed FireFox on your Windows, Mac or Linux computer!

This is quite a record for a browser and this is the complete FireFox 2 veulnerability report ... just 2 vulnerabilities and just one of them unpatched and it's a less critical problem.

This is "your" Internet Explorer 6 vulnerability report and this is the last version 7 of, again, Internet Explorer Browser vulnerability report with 3 bugs, one of them moderately critical and any of them patched.

So c'mon guys, what are You waiting for ? GetFirefox ;-)

Tuesday, December 19, 2006

IWA Italy didn't choose me !!!

The Web Skills Working Group selection is closed and the group is complete.

A lot of University members, a lot of Information Architect and a lot of IWA members ... but "any every day applications" certified or skilled developer, just people that write books, blog posts, do training courses every day and probably part of the same trainings that make italian ICT as is right now (unlikely often generally "ridi.culo.us" ...) ... well, I can't read about any skilled server and client (both!) developer in the Web 2.0 era (or probably I don't know Him/Her) ... but this group should tell us how should be a Web developer and what kind of certification He should have to be a real Web developer ... sure, one or more IWA certifications !

At this point, my first opinion is that V.U.E. certifications aren't a good start point (I've 2 official server and client certifications,PHP Engeener and AS2.0 - ECMAScript 3/4 Developer) and that my W3C/PHP/JavaScript/ActionScript skill and experience (about 8 years) isn't enought to be part of choosed professionists group ... I'm quite disappointed about that but I really ... really hope that next 3 months will be a revolution for italian Information and Communications Technology !

Well, Good Luck Web Skills Working Group, I hope you'll do an excellent work and I hope you'll find the right way to create real good Web developers and not just "fake Web Doctors" !!!

I'm waiting for your progresses, please respect our expectations, we believe in you ! :-)


[update]
this is just my opinion wrote in an italian forum

Sunday, December 17, 2006

Reset The Element CSS

Few days ago ajaxian posted a YUI solution to reset CSS in a page.

This is a really interesting way to solve inherit CSS problems when You need to create a personal widget or when a library would do it.
Dean Edwards did a WHATWG proposal for a <reset> element because
He *really* wants to turn off CSS inheritance
.

He's quite right for many reasons and that's mine proposal, a reset css that just use simply a class name.

.reset,.reset div,.reset dl,.reset dt,.reset dd,.reset ul,.reset ol,.reset li,.reset h1,.reset h2,.reset h3,.reset h4,.reset h5,.reset h6,.reset pre,.reset form,.reset fieldset,.reset input,.reset textarea,.reset p,.reset blockquote,.reset th,.reset td
{margin:0;padding:0;}

.reset table
{border-collapse:collapse;border-spacing:0;}

.reset fieldset,.reset img
{border:0;}

.reset address,.reset caption,.reset cite,.reset code,.reset dfn,.reset em,.reset strong,.reset th,.reset var
{font-style:normal;font-weight:normal;}

.reset ol,.reset ul
{list-style:none;}

.reset caption,.reset th
{text-align:left;}

.reset h1,.reset h2,.reset h3,.reset h4,.reset h5,.reset h6
{font-size:100%;font-weight:normal;}

.reset q:before,.reset q:after
{content:'';}

.reset abbr,.reset acronym
{border:0;}


The element with reset class name and every "resetted" elements seems to work fine and You could see an example using this page changing the href of the style element and changing, for example, the body element in this way

...
<link rel="stylesheet" type="text/css" href="reset.css">
</head>

<body class="reset">
...


This is just an example because You could use reset with every element to obtain the same result for each nested table, form and elements.

This isn't probably the best solution but should be one solution and You could use multiple class name to define Your style too

...
<element class="reset mywidgetstyle">
...


There's only some adjustment to do with headers and probably something else that You could set using a dedicated css

.reset h1 {
font-weigth: bold;
font-size: 1.2em;
}


It's just an example but it should work with every CSS based browser.

What do You think about this solution ?

Saturday, December 16, 2006

A stupid Ajax cache problem solution

One of the common problem using Ajax (Flash too) interactions is the cache.
There are a lot of valid PHP, Python, JSP and .NET solutions but browser compatibility is often a question mark.

You could implement easyly and directly a client solution and this is just another proposal.

function noCache(uri){return uri.concat(/\?/.test(uri)?"&":"?","noCache=",(new Date).getTime(),".",Math.random()*1234567)};

exactly 123 bytes to solve cache problems and this is the func description:

function noCache(
uri
// uri string to open
){

return uri.concat(
// concat String prototype,
// the fastest way to produce
// a complete string using multiple values

/\?/.test(uri) ?
// if uri has a query string

"&"
// add last value using & separator char
:

// else
"?",
// add a query string to this url

"noCache=",
// this should be a "cool name" for generated key

(new Date).getTime(),
// the noCache value will be milliseconds
// from 1970/01/01

".",
// plus a dot ...

Math.random()*1234567
// ... and a random value using
// a "big" integer as generator
);

// then this is a return example using uri: http://host.com/mypage.html
// http://host.com/mypage.html?noCache=1166301156233.332083.6663326991

// while this is an example using uri: http://host.com/mypage.html?v0=1&v2=a
// http://host.com/mypage.html?v0=1&v2=a&noCache=1166301168420.631416.7190624559
};


You could test directly in a loop, a benchmark that many other sites didn't test ...

for(var
i = 0, // many loops
max = 10000, // max i value
uri = document.location.href, // this href
obj = {}; // a generic object
i < max; // while i is less than max
i++ // increment the i value
) {
if(!obj[noCache(uri)]) // if obj has not a nocache(uri) key
obj[noCache(uri)] = true; // set them as true
else { // else if obj has just the returned nocache(uri) key
i = max;
alert("noCache doesn't work"); // this method is not so cool
}
};


A script that use Ajax requestes inside a loop is not a good script (I suppose) but this kind of demostration can show You that generated no-cache collisions probability are quite impossible.

A usage example should be this one:

XHR.open("get", noCache(myUri), true);
// or ...
XHR.open("post", noCache(myUri2), true);


Finally these are some F.A.Q.

Why there is a key and a value and not just a random value to perfom without caching problems ?
- because some server-side code should loop over GET or POST keys and in this way it should know that noCache is a not useful parameter to parse or to check. In other cases a server-side code should consider generated radom value as a key.

Why there is a getTime plus a random value and not just the first one ?
- because some client application should call more than a single request at the same time

Why there is a full stop between getDate and random value ?
- because if client date is modified there are less possibilities that generated value was just used (paranoia style)

I think these F.A.Q. are enought and I hope You'll find this simple function useful :-)

P.S. with ActionScript just change the regExp replacing with uri.indexOf("?") >= 0

Thursday, December 07, 2006

The byte family is now complete, welcome bytedom

another "$" dollar function ? elements prototypes ? no, just a simple library with its namespace that doesn't modify anything else !
This is my last creation to complete my lightweight low-level framework that should be everything You need for your Web 2.0 sites or to develop more complex libraries too.

I've found EJ idea great but I always look for my own solutions.
I've thought about bytedom since I've created btefx but btesonwas more important than simply dom management (P.S. new byteson version 2.0b is available) but now I've completed what I need to develop my projects.

This is the bytedom method list:

  • addClassName, to add if not present a class name to an element

  • addEvent, to add a standard name event such click, load, mouseover and every other, DOMContentLoaded too

  • clear, to remove empty textnode from an entire document (FireFox, for example, reads newlines as textnodes)

  • create, to create one or more elements (input, div, span .. and every other)

  • every, a method like Array.every official JS 1.5 method, usable with a list of elements and arrays too

  • filter, same style of every, to get only what You need with your dedicated filter function

  • forEach, as every and filter, to do something with a list of nodes / elements or arrays too

  • get, something like dollar function, to get one or more elements with specified ids, lists of nodes of specified types or a list of elements with specified classNames

  • getStyle, to know a property of a specified element style

  • pop, to get and remove an element from a parent node

  • preventDefault, to prevent events defaults

  • push, to get and add an element at the end of a parent node (something like appendChild)

  • remove, to get and remove an element from a parent node

  • removeClassName, to remove a className, if present, from an node / element

  • removeEvent, to remove a standard name event such click, load, mouseover and every other, DOMContentLoaded too

  • replace, to get and replace a new node from a parent

  • reverse, to reverse the order of every child found inside a parent node

  • shift, to get and remove the first element of a parent node

  • some, as every, filter and forEach

  • text, to get and create one or more text nodes

  • toggle, to hide an element storing its old visibility and display style values ... and to assign them if element is toggled again

  • unshift, to add one or more element at the top of a parent node


These useful methods (at least in my humil opinion) let you get, modify, filter or manage dom elements in a simple, funnny (?) and JS friendly way.

This is just one of examples present in this page while this is a new anti pixel logo for people that use every byte library:
byte family
that with every member is less than 10 Kbytes for packer version, less than 15 Kbytes for clean crunched version and finally less than 7 for memtronic version.

Please sorry for incomplete bytedom site, I'll update API section as soon as I can.
Now, You could read about every method and parameters directly inside Open Source file version.

I hope you'll like new bytedom library and please tell me if something doesn't work correclty or some browser is not compatible (successful tested with IE5+, FF1+, Opera8+, Safri2+, KDE3.4+).

Wednesday, November 29, 2006

W3 Validator, DOM, byteson and PHP

I've uploaded a new byteson example page, based on a single and simple request to a PHP page that uses W3 Validator service, calling a SOAP result, parse them to convert it into an associative array and finally send it with JSON to byteson.

Here is the PHP code

<?php
// byteson filter
if(isset($_POST['byteson'])) {

// http://www.phpclasses.org/browse/package/3512.html
require 'FastJSON.class.php';

// http://www.devpro.it/code/143.html
require 'W3validator.function.php';

// remove magic quotes if th it's present
// magic_quotes is a problem for JSON strings
if(get_magic_quotes_gpc())
$_POST['byteson'] = stripslashes($_POST['byteson']);

// get the output
$output = FastJSON::encode(W3validator(FastJSON::decode($_POST['byteson'])));

// force new content to download
header('Content-Type: text/plain; charset=utf-8');
header('Content-Length: '.strlen($output));
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');

// exit writing JSON object for byteson
exit($output);
}
?>

This code is above the xHTML output and You can view them by yourself, viewing the example page.

This php page uses two other files, my FastJSON class and my last function on devpro, called W3validator (what a fantasy ...).

The JavaScript code is this one

// new browsers filter
if(document.getElementsByTagName)
onload = function(){ // (C) Andrea Giammarchi

// assing tabindex and accesskey
function accesstab(input){
input.accesskey = input.tabindex = ++accesskey;
++tabindex;
};

// assign generic link properties
function addLinkProperties(a){
tab(a);
a.href = "#";
a.onclick = function(){
var ul = this.parentNode.getElementsByTagName("ul").item(0);
ul.style.display = !!ul.style.display ? "" : "none";
return false;
};
return a;
};

// append one or more elements into another
// then return the "parent" element
function append(parent, elements){
if(elements.constructor !== Array)
elements = [elements];
for(var i = 0; i < elements.length; i++)
parent.appendChild(elements[i]);
return parent;
};

// create a list if there are errors or warnings
function createList(message, obj){
for(var a, span, i = 0, key = "", list = [], tmp = []; i < obj.length; i++) {
for(key in obj[i]) {
span = node("span");
span.innerHTML = obj[i][key];
tmp.push(append(
node("li"), [
append(node("strong"), text(key)),
span
]
));
};
a = addLinkProperties(append(node("a"), text(message.concat(i + 1))));
list.push(append(node("li"),[a, append(node("ul"), tmp)]));
tmp = [];
};
return append(node("ul"), list);
};

// perform the request using byteson
function doRequest(oldtab){

// just call the server side page
// sending input string and adding just
// one listener ( because I'm sure, this application will works "perfectly" :P )
byteson.request("w3validator.php", inputuri.value, {

// onload event
load:function(obj, xhr){
var a, key = "";

// remove the loading text
resultlist.removeChild(resultlist.firstChild);

// create a list with every key value ...
for(key in obj) {

// but not with Arrays (errors or warnings)
if(obj[key].constructor !== Array) {
append(
resultlist,
append(
node("li"), [
append(node("strong"), text(key)),
append(node("span"), text(obj[key]))
]
)
);
};
};

// create last list with each error or each warning
for(key in obj) {
if(obj[key].constructor === Array && obj[key].length > 0) {
a = addLinkProperties(append(node("a"), text(key)));
append(
resultlist,
append(
node("li"), [
a,
createList(key.replace(/list/, ' #'), obj[key])
]
)
);
a.onclick();
};
};

// enable the form
inputuri.disabled = senduri.disabled = false;

// set old tabindex for next request
// (correct tab navigation ready)
tabindex = oldtab;
}
});
};

// create and return an element of specified type
function node(type){return document.createElement(type)};

// add tabindex property using global scpe tabindex integer value
function tab(node){node.tabindex = ++tabindex};

// create and return a text node with specified content
function text(value){return document.createTextNode(value)};

// internal global scope variables
var accesskey = 0, // accesskey (WCAG ready ?)
tabindex = 0, // tabindex (tab navigation ready)
output = document.getElementById("request"), // div container
form = node("form"), // used form
inputlabel = node("label"), // label for input text
inputuri = node("input"), // input text
sendlabel = node("label"), // label for send button
senduri = node("input"), // send button
resultlist = node("ul"); // result unordered list

// assign accesskey, tabindex and other parameters for each input (in this case text and btn)
accesstab(inputuri);
inputuri.type = "text";
inputuri.id = inputlabel["for"] = "userinput";
// keyboard event listener (RETURN to perform the request)
inputuri.onkeyup = function(evt){
if(!evt)
evt = window.event;
if(!evt.wich)
evt.wich = evt.keyCode;
if(evt.wich === 13 && this.value.replace(/^\s*|\s*$/, '').length > 4)
senduri.onclick();
};

accesstab(senduri);
senduri.type = "button";
senduri.id = sendlabel["for"] = "sendinput";
senduri.value = "verify";
// request function
senduri.onclick = function(){
var newresult = node("ul");

// disable the form
inputuri.disabled = senduri.disabled = true;

// blur this button
senduri.blur();

// remove precedent unordered list element and replace
// replace them with a simple "loading response" message
// inside a new unordered list element
resultlist.parentNode.replaceChild(newresult, resultlist);

// assign new ul element to global scope var (to change them on load)
resultlist = newresult;
append(resultlist, append(node("li"), text("loading response")));

// perform the request with byteson
doRequest(tabindex);
return false;
};

// form should be disabled, by default
// (the form doesn't degrade in this example)
form.onsubmit = function(){return false};

// create the output only for the first time
output.replaceChild(
append(
form, // the form
append(
node("fieldset"), [ // top fieldset
append(
node("legend"), // and its legend
text("W3 Validator") // with its content
),
append(
inputlabel, // label for text input
text("write a valid url address") // and its content
),
inputuri, // input text
append(
sendlabel, // label for button
text("verify W3 validator result") // and its content
),
senduri // send button
]
)
), output.firstChild);

// create result fieldset to show informations
// append this fieldset after the precedent output
append(
output,
append(
node("fieldset"), [ // bottom fieldset
append(
node("legend"), // and its legend
text("W3 Response") // with its content
),
resultlist // and its unordered list
] // to show the result
)
);
}; // that's all


The last file is the external stylesheet used in this page.

This basic example can explain better than every post, how W3validator PHP function works and how much is simple to implement byteson inside other JS code.

Have fun with W3 validation ;-)

Friday, November 24, 2006

My Last DOMContentLoaded Solution

Update 28/11/2006 Thanks to anonymous for its perfect suggest!!!
Update 01/12/2006 Thanks to Stephen Elson for debug
Update 01/13/2007 This is my last version that doesn't use global window.__onContent__ variable
Update 13/02/2007
Sorry guys for my choosed old title, thanks to Pierluigi that explained me what did it mean




function onContent(f){//(C)webreflection.blogspot.com
var a=onContent,b=navigator.userAgent,d=document,w=window,c="onContent",e="addEventListener",o="opera",r="readyState",
s="");
a[c]=(function(o){return function(){a[c]=function(){};for(a=arguments.callee;!a.done;a.done=1)f(o?o():o)}})(a[c]);
if(d[e])d[e]("DOMContentLoaded",a[c],false);
if(/WebKit|Khtml/i.test(b)||(w[o]&&parseInt(w[o].version())<9))(function(){/loaded|complete/.test(d[r])?a[c]():setTimeout(arguments.callee,1)})();
else if(/MSIE/i.test(b))d.write(s);
};



Here is where this "story" began, inside a Dean Edwards post.
After that there was a big list of comments, posts and tests ... for a second post and a better solution !

Dojo adopted that solution ... then came back to old one ... but someone has never stopped to test, to try or to find a "perfect" way to add DOMContentLoaded with every browser and expecially with Internet Explorer.

Mark Wubben and Paul Sowden did it, they've created a complete and portable solution that works with http and https pages too !

Wonderful work guys and ... as first point, thank you very much !


Now, I can show my personal DOMCOntentLoaded solution, explaining them as better as I can.


The first step, the real key of this code, is the source of used script.

It's not void, it's not //0 ... it's exactly this one: //:
and is what I had not to create my tiny, simple and portable solution.

Here is the func, called onContent ...

function onContent(f){//(C)webreflection.blogspot.com
var a,b=navigator.userAgent,d=document,w=window,
c="__onContent__",e="addEventListener",o="opera",r="readyState",
s="<scr".concat("ipt defer src='//:' on",r,"change='if(this.",r,"==\"complete\"){this.parentNode.removeChild(this);",c,"()}'></scr","ipt>");
w[c]=(function(o){return function(){w[c]=function(){};for(a=arguments.callee;!a.done;a.done=1)f(o?o():o)}})(w[c]);
if(d[e])d[e]("DOMContentLoaded",w[c],false);
if(/WebKit|Khtml/i.test(b)||(w[o]&&parseInt(w[o].version())<9))
(function(){/loaded|complete/.test(d[r])?w[c]():setTimeout(arguments.callee,1)})();
else if(/MSIE/i.test(b))d.write(s);
};


... and this is the http test page, while this is the https test page.



Let me explain that unreadable function with a clear commented version :)


function onContent(callback){ // (C) webreflection.blogspot.com
// [please note that this code doesn't work]

// private scope variable

var IEStringToWrite = // this is IE dedicated string

"<script defer src='//:' onreadystatechange='
(function(element){

// if readystate is complete
if(element.readyState === "complete") {

// remove the element
element.parentNode.removeChild(element);

// call the global variable
window.__onContent__();
}
})(this);
'></script>";

// the above string is necessary to use onreadystatechange property
// with an undefined page. In this way IE tell us the readyState
// of the current document



// to call callback function IE need a global scope variable
// this variable could call one or more callback
// then if it's already created we need to call the old callback
// then this new callback
window.__onContent__ = (function(oldCallback){

// returns a function that will set every callback fired
// [thanks to Stephen Elson for its suggest]
// to remove multiple callbacks with different
// events and different ways for each browser

return function(){

// set window.__onContent__ as empty function
// required by IE5
window.__onContent__ = function(){};

// verify that callee wasn't fired before
if(!arguments.callee.done) {

// set calle.done 1 as true fired value
arguments.callee.done = 1;

// checks if oldCallback isn't null or undefined
if(oldCallback)
oldCallback(); // call them to preserve the right order

callback(); // call this scope callback function
// (sent calling onContent)
}
}

})(window.__onContent__); // undefined if is the first time we use __onContent__



// __onContent__ is my function to use as callback

// I need to add this function as event

// Opera 9 and FireFox both support DOMContentLoaded as well as
// addEventListener document method
if(document.addEventListener)
document.addEventListener("DOMContentLoaded", __onContent__, false);

// if some browser supports addEventListener but doesn't support DOMContentLoaded
// event I don't need to care about that because this event will never be fired

// at the same time if Safari or KDE one day will support DOMContentLoaded
// I prefere use this dedicated in-core
// event instead of next trick that's quite horrible but works with Safari,
// KDE as Opera 8.5 and lower too

// that's why I don't use an else if but an if ... because the first time
// event will be fired __onContent__
// became an empty function ... then calling them twice is not a problem

if(
// Safari and KDE
/WebKit|Khtml/i.test(navigator.userAgent) ||

// Opera less than 9
(window.opera && parseInt(window.opera.version())<9)
)
// runtime anonymous function
(function(){

// checks if document.readyState is loaded or complete
/loaded|complete/.test(document.readyState) ?

// then call __onContent__ , stopping internal loop
window.__onContent__() :

// or loops itself with the faster timeout
setTimeout(arguments.callee, 1);
})();

// at this point I've setted the DOMContentLoaded event for every browser
// but not for Inernet Explorer.
else if (/MSIE/i.test(navigator.userAgent))

// I can write dedicated string
document.write(IEStringToWrite);
};



My solution doesn't use conditional comments (I hate them !!!) ... and this is the compatibility list:

- FireFox 1 or greater
- Opera 8 or greater (I don't know 7)
- Safari 2 or greater (I don't know 1)
- KDE 3.4 or greater
- Internet Explorer 5 or greater (I don't know IE 5.2 for Mac)

Tuesday, November 21, 2006

Wall Street and GOOG , the day after the record

This is why they show beta logo, this is what should happen to bigs too.




Who caused the problem ? :)

Monday, November 20, 2006

CSS dropshadow ? Sure, simple and unobtrusive !

My favourite italian portal wrote a post about a CSS based dropshadow solution.
It talks about this webtoolkit.info post.

I didn't know that article then only now I can tell You something about that:

  • graphic effects are good "only" for high bandwidth web surfers
  • dropshadow isn't important as page content
  • id attribute should be absolutely unique
  • markup language has a scope and should be used for this scope (sure, when it's possible)
  • 5 nested divs just to show a simple shadow effect aren't a cool solution (imho)


Since You can do the same thing using a really basic JavaScript function without a repeated id, nested obsolete elements and in a cross browser way with about 1.8 Kb of uncompressed and goo JavaScript, I think You should think about my alternative proposal.

The only things You need is a better CSS, not based on id but based on class name and a simple callback.
This is revisited CSS

/* CSS container shadow */
.shadow-container {
position: relative;
left: 3px;
top: 3px;
margin-right: 3px;
margin-bottom: 3px;
}
.shadow-container .shadow2,
.shadow-container .shadow3,
.shadow-container .container {
position: relative;
left: -1px;
top: -1px;
}
.shadow-container .shadow1 {
background: #F1F0F1;
}
.shadow-container .shadow2 {
background: #DBDADB;
}
.shadow-container .shadow3 {
background: #B8B6B8;
}
.shadow-container .container {
background: #ffffff;
border: 1px solid #848284;
padding: 10px;
}
/* CSS container shadow */


And this is simple callback example:

onload = function(){
createDropShadow(
getElementsByClassName(
document, "div", "dropshadow"
)
);
};


Now You can use a dedicated dropshadow div class name in every div that You want to modify.

<div class="container dropshadow">
Lorem Ipsum ...
</div>


That's all, just include ej basic file and my dedicated function and You'll have a cleaner page without nested divs overloads and ... bye bye nested divs :)

Thursday, November 16, 2006

New Ajaj library on the net ! Welcome byteson

byte familiy is growing up and it's first "son" is called byteson.

byteson is a lightweight Ajaj library that could send and recieve in a simple way every JSON compatible variable.

byteson is server side language indipendent and it's naturally compatible with UTF-8 charset.

Finally, byteson is small, less than 2Kb Memtronic Version, about 3Kb packed and should be the only thing You need to create advanced client-server interaction.

Do You like it ?

byteson logo

Here You can find a portable txt summary of this library :)
byteson.txt

Monday, November 13, 2006

Unobtrusive Password Security Level Form

Few days ago I've put two JavaScript and PHP simple functions on devpro.it, called password security.

Today I would show You hot to use thoose functions, creating a valid W3 and WatchFire form to set or update one password with security level informations.
Security Level is a simple graphic/textual element used, for example, when You create a Windows Live account.

This kind of information is really useful for users because they've to choose at least a medium security password to have a "secure" account.

That's why I've created this example page and now I'm telling You how I did them.



First step, external files
I've saved PHP and JavaScript dedicated functions in different files.
Then I've created an external CSS file too and a simple graphic bar:
psl graphic bar

It's dimension are the same of element that will show this bar.

CSS important things are p.pwdlevelN informations, used to show background image with differents positions.



Next step, procedural PHP code
Example page uses few PHP lines of code, and thoose need to show different pages if user hasn't JavaScript support (or He has JS disabled) with or without a notice message.
This is used code:


// array with every password security levels
$security_levels = array('not secure', 'low security', 'medium security', 'high secutiry');

// if user choosed a password
if(isset($_POST['pwd'])) {

// include psl function [http://www.devpro.it/code/141.html]
require 'psl.php';

// get security level
$level = psl($_POST['pwd']);

// create an element with security level informations
$security_informations =
'

'.$security_levels[$level].'

';

// show message if password has been approved
if($level > 1) {
$security_informations .= 'password successful setted
';

// do stuff, for example change password on db
}
else
// just show a message about bad security
$security_informations .= 'please choose a better password
';
}
else {

// create default element
$security_informations = '

';
}

// create output
?>

As You can see, this code is really simple and sure, basic too but is useful to understand why whe need PHP to create an unobtrusive JS like page.



Next step, JS code, using PHP too
Since I've defined an array without special chars, I could use them to create same JavaScript array too while other code is used to enable or disable submit button showing security level under the password input.

// returns an element by id
function $(id){
return document.getElementById(id);
};

// checks password security, enables submit if it's secure
function checkSecurity(inputId, securityId, submitId){

// array with every password security levels (simple with a php variable)
var security_levels = ["<?php echo implode('","', $security_levels); ?>"];

// get security level
var level = psl($(inputId).value);

// create an element with security level informations
var security_informations = document.createElement("P");
security_informations.id = securityId;
security_informations.className = "pwdlevel".concat(level);
security_informations.appendChild(document.createTextNode(security_levels[level]));

// switch the old information element with new one
var oldinformations = $(securityId);
oldinformations.parentNode.replaceChild(security_informations, oldinformations);

// enable submit if password is secure enought
$(submitId).disabled = level < 2;
};

// clean pwd value and disable the submit
onload = function(){
$("userpwd").value = "";
$("setpwd").disabled = true;
}

Just a note about DOM, Internet Explorer is not compatible with standard (what a news ...) setAttribute HTMLElement method, then I've used direct assignment for id and className.




Final step, W3 / WCAG compilant layout
To show security level and to choose the new password, I've used a standard output that should be compatible with every browser from IE 5 to 7, FF 1 to 2, Opera 8 and 9 and maybe 7 too.
I've not tested KDE, Safari and Camino but I hope these browsers will don't have any problem with simple code used.
You can see full used code in this page.



I hope this example page will be a start point to create your own password security level area.

Saturday, November 11, 2006

Which function to get an XMLHttpRequest object ?

Ajax is "quite old" but I've not found any crossbrowser clean or standard way to create and return the correct XMLHttpRequest.

I wrote a standard crossbrowser function in my italian Ajax Guide (http://javascript.html.it/guide/leggi/95/guida-ajax/) but someone, every day, try to discard that function or to create a "new way" to get that object.

My opinion is this one:
- You don't need any conditional comment, these aren't a good code practice
- You don't need any evil eval function ... You can do your check without problems
- You don't need any try catch, first because they're not compatible with old browsers, second because You can simply check browser version and then choose the correct ActiveX, if it's necessary


Then, if You're looking for a simple, fast and cross browser way to get XMLHttpRequest You could just use this function:


function xhr(){ // webreflection.blogspot.com
var xhr = null,
b = navigator.userAgent;
if(window.XMLHttpRequest)
xhr = new XMLHttpRequest();
else if(!/MSIE 4/i.test(b)) {
if(/MSIE 5/i.test(b))
xhr = new ActiveXObject("Microsoft.XMLHTTP");
else
xhr = new ActiveXObject("Msxml2.XMLHTTP");
};
return xhr;
};


Every compatible browser, FF 1+, Opera 8+, Safari 2+, KDE 3.4+, IE 5+, will get a valid XMLHttpRequest while every other browser, for example IE4, will recieve a null value.
Then You can simply verify if client browser support Ajax request using a sintax like this one:

var ajax = xhr();
if(ajax)
// do every async interaction ...


That's all, I hope this will be helpful :)

Friday, November 10, 2006

PHP and JavaScript encoding comparison table

PHP and JavaScript are used every day for sync or async interactions.

I often read functions or libraries that use JS escape function and I often read forum discussions where someone writes that to solve chars problems You need to use escape function.

That's wrong, as is the usage of urlencode instead of rawurlencode.



What's wrong on PHP urlencode function ?
urlencode works quite perfectly with different charsets but has a big problem expecially with one char, the space char " ".
This char is not escaped but is replaced with a "+" sign.
If You write an url with this sign instead of a space there are no problems but if write a response for JavaScript with this char there are different problems.

As You can see from this comparative table JavaScript escape or encode perfectly the space char but doesn't escape the plus sing "+".
This means that when You'll unsecape an urlencoded string it will convert plus sign correctly.

To solve this simple but common problem, when You need to encode a PHP string, use always the raw version: rawurlencode.




What's wrong on JavaScript escape function ?
It has more and more problems than urlencode PHP function because it is an old function (too much) with the best encoding browsers compatibility but without unicode support.
The first point is that it doesn't escape correctly the plus sign, then if You send an escaped string with a simple addiction "1 + 2 = 3" to PHP page, it will recieve a string like this one "1 2 = 3" because PHP urldecode function converts plus sign into a space.
However, the real big problem with escape is that it doesn't support unicode and it converts "correctly" only ASCII chars.

For example at the end of comparative table You can view that escape converts only in range 0x00 - 0xFF but doesn't convert in UTF-8 compatible way every char in range 0x80 - 0xFF and produces, for example, a string like "%E0" that's not the correct multibyte utf-8 rappresentation of char #224.

If You read under this line You can see that escape cannot produce a compatible output for unicode chars in a cross language compatible way.

I mean that every multibyte char in range 0x0100 - 0xFFFF will be converted into a fake JSON rappresentation: %u0100 - %uFFFF that isn't absolutely a correct encoded char and isn't compatible with any other language or url string specs too.

You can use escape only if You send, and recieve, simple strings like [0-9a-zA-Z] with some extra char ( \w ) but isn't absolutely a portable and correct way to create iso or utf-8 PHP and JavaScript interactions.

Tuesday, November 07, 2006

not yield and the shortest Fibonacci function

I was joking with new JS 1.7 features, well documented in this page, when I've thought about yield keyword.

It's a strange keyword because isn't usable as the rest of JS code.

For example, alert(yield variable) generates an error but alert((yield variable)) shows an undefined value.
(I know, it is quite idiot to think that it should have some value ...)

Then I've done some test:

function fakeGenerator(){
var i = 0;
while(true)
// alert(yield i++); // error
// alert((yield i++)); // undefined
yield i++; // ok
};


As you can see, (yield something) returns an undefined value and then this is a true expression.

!(yield variable) === true


Now You can think that a while loop should use this condiction instead of while(true) {yield variables;} ... for example:

function fakeGenerator(i){
while(!(yield i++)){}
};

works perfectly then maybe I could use this information to write something like this ?

function fakeGenerator(i){
while(!(yield i++));
};

Sure, and it works perfectly again !!!
!undefined is true and semi colon stops while loop then with an "OR" or an "AND" and a true value as condiction I could create a lot of dirty generators ... why not Fibonacci too ?

function fib(){
let(i=0,j=1){
while((yield i)||([i,j]=[j,i+j]));
}
};

so c'mon brother, you can do it better!, said my dog ... and He was right, I can remove even OR, parentheses and why not, the last semi colon too (thanks to let block).

function fib(){let(i=0,j=1){while(!(yield i))[i,j]=[j,i+j]}};

That's what I meant for the shortest Fibonacci function, isn't that ?!?



Then ... What's up ?
I wrote this stupid post just to tell You that sometimes You don't need the "while(true)" condition, just switch true the "undefined yield" :)

Thursday, November 02, 2006

bytefx 0.4

The good thing is that bytefx now has a new scroll method, the sad thing is that Safari 2 probably doesn't work with MemTronic compressed version and this new method cost about 1 more Kb, then bytefx now is 2.09 Kb and not less than 2 ... however, it is not so important because packer version is less than 3Kb and more compatible with Safari 2 too.

Fixes: any fix, bytefx seems to be really stable and probably bug free (simple with few lines of code :D).

Changes: just a new method to scroll the page with elements as target.

Visit the faq page to view an example.

Simple, cool ? Hey guys, It's bytefx ;)

Wednesday, October 25, 2006

What time is it ?

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

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.

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)


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:
  • 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 :)

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 !

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)

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

// "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

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 :-)

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

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:

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 :)

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 ?

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.

<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

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.