I would like to introduce some ideas about our vision of the framework.
Lot's of Ajax frameworks come with cross-browser compatibility. That's a good point. But still they are working with DOM Element.
We introduced new elements called LDOM Element.
The priniciple is that for each important DOM Element on the web page, you have a corresponding LDOM Element.
From your script, you don't "speak" to DOM Element anymore, but with theses LDOM Elements. Beyond that, LDOM Element are pure Javascript Objects so they are faster to query.
I have made up a mere example of a property access to a DOM Element and to the same DOM Element, but through the LDOM Element. This is made possible because the LDOM Element listen to the changes of it's DOM and update it's value.
Let see DOM access vs LDOM access.
17 February, 2006
31 January, 2006
the wonderfulness of eval( ) and setTimeout( )
If have been diggin' into delaying code execution without context loss.
One knows that when using setTimeout, you loose the context you where in when calling that function.
The idea is to make javascript take a picture of the context, wait, wait, then execute some code in that memorized context. Plus, I want the way to do that being easy to understand and natural to write.
So I came up with a couple of functions, each with a certain role to play:
1. We need a global variable that stack the contexts and unstack them when time is out!
2. We need an easy way of writing code to be executed.
The solution here is to encapsulate the code within an anonymous function that we will call when time is out within the unstacked context! Wonderful, isn't it ?
And here comes the code:
And the magic operates!
One knows that when using setTimeout, you loose the context you where in when calling that function.
The idea is to make javascript take a picture of the context, wait, wait, then execute some code in that memorized context. Plus, I want the way to do that being easy to understand and natural to write.
So I came up with a couple of functions, each with a certain role to play:
1. We need a global variable that stack the contexts and unstack them when time is out!
2. We need an easy way of writing code to be executed.
The solution here is to encapsulate the code within an anonymous function that we will call when time is out within the unstacked context! Wonderful, isn't it ?
And here comes the code:
//A function that returns unique IDs
//(it's like a class with a class attribute)
getId = function() {
if (!this.id)
this.id = 0;
this.id++;
return this.id;
}
//A function that acts like a stack (registers objects by unique IDs)
registerObject = function(objType, id, o) {
if (!this.objById)
this.objById = new Array();
if (!this.objById[objType])
this.objById[objType] = new Array();
if (this.objById[objType][id])
alert('Object already registered with this ID!!');
else
this.objById[objType][id] = o;
}
//A function that unstacks the registered object with a given ID
getObjectById = function(objType, id) {
return this.objById[objType][id];
}
//We use objType for our stack to be reusable
//in other parts of our program
//This way, the stack can hold several object in different use contexts
//A test class to be instantiate
testClass = function() {
//Attribute
this.phrase = 'Cool! The context is saved!';
//Method with reference to the class object
this.doSomething = function() {
alert(this.phrase);
}
}
//The function that delay code execution
delay = function(code, contexte, time) {
//We provide a unique ID for our context object to be memorized
var id = getId();
//We register our context object in the stack
registerObject('delay', id, contexte);
//When time is out, the code will be evaluated within the stacked context
setTimeout('eval('+code+'.call(getObjectById(\'delay\','+id+')));', time);
}
//Then we run the test!!
//Instantiate the test class
var myTest = new testClass();
//Call a method right now
myTest.doSomething();
//Call the same method in 5 secondes
delay(function() { this.doSomething(); }, myTest, 5000);
And the magic operates!
18 January, 2006
width percentage issue
In a previous post, I already pointed out the difference between IE and Firefox concerning the width property when set in pixel.
It appears to work the same way when this property is set in percentage.
Indeed, try setting the width of a bordered DIV to 100% of the BODY. For example, the DIV has a classic 1px black border. The body, depending of your screen resolution and the size of the IE (or Firefox) window, could be 950px large. On IE, you get a DIV which width is 950px (948 + 2 for the borders). That's what you expect, right ?
On Firefox, you get a DIV which width is 950px. But remember, on Firefox, the padding and border are not included, so you get a border-to-border width of 952px (950 + 2 for the borders) and a hugly horizontal scrollbar at the bottom of the page. Plus, you don't see the right border of your DIV ! That's not really what you expected !?
See my width percentage issue sample for the visual proof.
04 January, 2006
HTML, DOM and Ajax Features
Thinking about the HTML tree and the DOM capabilities, I come to the conclusion that you can very easily apply an Ajax feature to several HTML element at the same time. What you need is to have a common parent for them and apply the feature to the parent. If the parent moves, fades, resizes, disappear, change font style, etc... the children elements will act the same.
What if you want to fade a thumbnail of a picture once the picture is faded ? God, you have to write specific code to indicate to fade the thumbnails each time a related picture is faded!
To me, it's a big lack in HTML that you cannot group elements otherwise than in a tree style. Worse, doing so, HTML tags are used both ways : for graphic rendering and for encapsulation. Think about two HTML DIV you want to move together. You will create a tird DIV that contains them. First two DIV : graphical ; Tird DIV : encapsulation.
In our framework, we introduce a non graphical element that contains graphical elements and responds to Ajax features as a graphical element would. This way, it is transparent for the developper to apply a feature to a graphical or a non graphical element. And there is NO DOM element which are used for feature managment.
See the difference between the two classes LDivElement and LDomListElement while in HTML it's always HTMLDivElement.
What if you want to fade a thumbnail of a picture once the picture is faded ? God, you have to write specific code to indicate to fade the thumbnails each time a related picture is faded!
To me, it's a big lack in HTML that you cannot group elements otherwise than in a tree style. Worse, doing so, HTML tags are used both ways : for graphic rendering and for encapsulation. Think about two HTML DIV you want to move together. You will create a tird DIV that contains them. First two DIV : graphical ; Tird DIV : encapsulation.
<div id="I'm here for non graphical reason">
<div>First DIV</div>
<div>Second DIV</div>
</div>
In our framework, we introduce a non graphical element that contains graphical elements and responds to Ajax features as a graphical element would. This way, it is transparent for the developper to apply a feature to a graphical or a non graphical element. And there is NO DOM element which are used for feature managment.
firstDiv = new LDivElement('first', 'First DIV');
secondDiv = new LDivElement('second', 'Second DIV');
group = new LDomListElement(firstDiv, secondDiv);
See the difference between the two classes LDivElement and LDomListElement while in HTML it's always HTMLDivElement.
23 December, 2005
Transmitting arguments from a function to another
Lately, I was wondering how one could call a function from within another function and passing the arguments without knowing them. I point this out because it is very tricky to debug such a thing and Javascript already has the perfect hack to do that!
Try the following :
It returns 3 as espected.
Now try the call from within another function like this :
It returns 1! Surprised ?
As arguments is just a special Array, it is transmitted to the test function as is.
So the test function receives only one argument which length is 3.
I have come up with the solution at the mozilla developer center.
The reserved words 'call' and 'apply' allow you to call a function in a different context than the function context. Using 'call', you give the context and the arguments, but using apply, you give the context and an array of arguments that becomes the arguments object of the called function! And that is just what we wanted.
Doing this :
It doesn't solve the problem, but doing that :
It returns 3 as espected. Here is how javascript itself solves the nested blind call!
Try the following :
function test() {
return arguments.length;
}
test(1,2,3);
It returns 3 as espected.
Now try the call from within another function like this :
function test_in() {
test(arguments);
}
test_in(1,2,3);
It returns 1! Surprised ?
As arguments is just a special Array, it is transmitted to the test function as is.
So the test function receives only one argument which length is 3.
I have come up with the solution at the mozilla developer center.
The reserved words 'call' and 'apply' allow you to call a function in a different context than the function context. Using 'call', you give the context and the arguments, but using apply, you give the context and an array of arguments that becomes the arguments object of the called function! And that is just what we wanted.
Doing this :
function test_in() {
test.call(this, arguments);
}
test_in(1,2,3);
It doesn't solve the problem, but doing that :
function test_in() {
test.apply(this, arguments);
}
test_in(1,2,3);
It returns 3 as espected. Here is how javascript itself solves the nested blind call!
21 December, 2005
IE memory leak
Several articles have been published about the IE memory leak. One has come to the conclusion that the leak appear when two objects from different worlds (DOM vs Javascript) refer to each other. Here is an example :
If you have this code in your page, you will see the corresponding iexplore.exe instance in your task manager increasing memory each time you reload . Here is the leak !
I have tried two things to avoid the leak, one was successfull.
The first thing I tried was to delete the reference from the Js object to the Dom object, writing this :
It doesn't work! So I decided to delete the reference from the Dom object to the Js Object :
And that worked. No more memory leak.
In conclusion, I have made up a reference cleaner which would delete Dom reference to Js objects before the page unload. That object is part of the Util class and is defined as follow :
each time you create a Js object that will refer to a Dom object, you register it to the collector by calling
and somewhere in your code, you add :
myDom = document.createElement('DIV'); //DOM world
myJs = 'foo'; //JS world
myJs.dom = myDom; //First reference
myDom.js = myJs; //Second reference, creating a cycling reference
If you have this code in your page, you will see the corresponding iexplore.exe instance in your task manager increasing memory each time you reload . Here is the leak !
I have tried two things to avoid the leak, one was successfull.
The first thing I tried was to delete the reference from the Js object to the Dom object, writing this :
myJs.dom = null;
It doesn't work! So I decided to delete the reference from the Dom object to the Js Object :
myDom.js = null; // or myJs.dom.js = null;
And that worked. No more memory leak.
In conclusion, I have made up a reference cleaner which would delete Dom reference to Js objects before the page unload. That object is part of the Util class and is defined as follow :
Util.collector = new Array();
Util.collector.register = function(object) {
this.push(object);
}
Util.collector.empty = function() {
for (var i=0; i < Util.collector.length; i++)
Util.collector[i].dom.js = null;
}
each time you create a Js object that will refer to a Dom object, you register it to the collector by calling
Util.collector.register( myJs );
and somewhere in your code, you add :
window.onunload = function() { Util.collector.empty(); }
13 December, 2005
the Util class
Introducing the class Util. Its a metling pot of methods that can be very usefull at any time when programming javascript. Theses methods are not meant for a particular type of object. For example, the dollar function ($) which is a shorthand for document.getElementById is not part of the Util class. It is in the Dom class as it plays with DOM Elements.
Here are some methods :
//A shorthand for document.write
Util.dw = function(str) {
document.write(str);
}
//You can alert multiple arguments send to that function
Util.alert = function() {
var str = '';
for (var i=0; i< arguments.length; i++) {
str += arguments[i];
if ( i != arguments.length-1 )
str += ' / ';
}
alert(str);
}
Here are some methods :
//A shorthand for document.write
Util.dw = function(str) {
document.write(str);
}
//You can alert multiple arguments send to that function
Util.alert = function() {
var str = '';
for (var i=0; i< arguments.length; i++) {
str += arguments[i];
if ( i != arguments.length-1 )
str += ' / ';
}
alert(str);
}
12 December, 2005
the layerX property in Firefox
When an element is clicked, you can get the mouse relative coordinates from the top left edge of the element with the e.layerX and e.layerY properties in Firefox. I discovered that the Firefox team made a change from version 1.0 to 1.5. In Firefox 1.0, if your mouse is over the very first top-left pixel of the element (including the border if existing), these properties indicates (0,0) as Safari 1.3 does. But in Firefox 1.5, these are (1,1) ! And you know what, I like the second way better. Because if your element is 200px width, you get layerX from 1px to 200px instead of 0px to 199px as if it was an array index.
On IE, it's very different because the equivalent which is event.offsetX gives you the number of pixel from the left border excluding the border! So that you can get a negative value if your element is bordered. And from the first inside pixel, it works like Firefox 1.0, giving you a 0.
This time, I would give the vote for Firefox 1.5 which convince me the best.
On IE, it's very different because the equivalent which is event.offsetX gives you the number of pixel from the left border excluding the border! So that you can get a negative value if your element is bordered. And from the first inside pixel, it works like Firefox 1.0, giving you a 0.
This time, I would give the vote for Firefox 1.5 which convince me the best.
09 December, 2005
Browser competition
Before going further in a framework implementation, I had a look at the Browser Statistics from w3schools. As they mention, it's only statistics, but I come up to the idea that my framework would be compatible with IE 6.0 and 7.0, Firefox 1.0 and 1.5, Safari 1.3 and 1.4 and Opera 8.5.
I will then gives you some feed back about cross-browser compatibility.
Let's begin with a simple example, the width style property of a DOM element.
Width is something abstract because from one browser to another, you don't see element the same size! In IE width is really what you see. It is the width of the element from one side to the other. In Firefox, width as a different meaning. It is the space available for displaying the child elements of a given element. On the screen, I would call it the internal width of an element. When you set the width of an element to a certain value, your element, from one side to the other as a total width of the value you specified plus the borders width plus the padding width.
Let's see an example of the width style property.
I will then gives you some feed back about cross-browser compatibility.
Let's begin with a simple example, the width style property of a DOM element.
Width is something abstract because from one browser to another, you don't see element the same size! In IE width is really what you see. It is the width of the element from one side to the other. In Firefox, width as a different meaning. It is the space available for displaying the child elements of a given element. On the screen, I would call it the internal width of an element. When you set the width of an element to a certain value, your element, from one side to the other as a total width of the value you specified plus the borders width plus the padding width.
Let's see an example of the width style property.
Introduction
I am developing web applications in Ajax technology for LUCCA. In the past days, I was asked to dig into the Ajax framework folk and to come up with ideas for our new application. The goal of this blog is to share my feed back on what I see on the web about Ajax framework. I will also try to present a bunch of functions that we could bring together to build a new framework.
Subscribe to:
Posts (Atom)