Keep in mind that this is very simple example. Our containers don't contain data and we don't have a backend ( i.e. PHP, JSP, etc. ). We're just going to persist layout and that's pretty easy to do with cookies.
Here's the example.
The general idea is that if the layout cookie isn't set, we'll show the default positions ( the default layout is already there; we've just set the display to "none" ). Otherwise, we'll layout based on what's found in the cookie.
What does the cookie look like?
Well, all of our containers ( "Container 1", "Container 2", etc. ) have static positions and are found in three columns. So, we'll use three subcookies ( c1, c2 and c3 ) where each subcookie contains a string consisting of element IDs. The cookie's name is "igoogimi" and expires every 14 days. If we were to look at the cookie on April 6, 2008, we'd see something like --
Name :: igoogimi
Value :: c1=Rec1%2CRec2&c2=Rec3%2CRec4%2CAbout&c3=Rec5%2CRec6
Expires :: Sun, 20 Apr 2008 05:41:55 GMT
Setting and getting a subcookie is pretty straightforward and it's well documented. Setting our subcookie is interesting because we use the method YAHOO.util.Dom.getChildrenBy to query the DOM looking for the column IDs. Here's our setCookies method --
var setCookies = function() {
// BEGIN :: Calculate cookie expiration to 14 days from today
var date = new Date();
date.setTime(date.getTime()+(14*24*60*60*1000));
// END :: Calculate cookie expiration to 14 days from today
var getNode = function(node) {
return (node.id==="Rec1"||node.id==="Rec2"||node.id==="Rec3"||node.id==="Rec4"||node.id==="Rec5"||node.id==="Rec6"||node.id==="About");
}
var createString = function(colId) {
var nodes = YAHOO.util.Dom.getChildrenBy(document.getElementById(colId), getNode);
var list = [];
var l = nodes.length;
for(var i=0;i<l;i++) {
list[i] = nodes[i].id;
}
return list.toString();
}
YAHOO.util.Cookie.setSub("igoogimi", "c1", createString("Column1"), {expires: date});
YAHOO.util.Cookie.setSub("igoogimi", "c2", createString("Column2"), {expires: date});
YAHOO.util.Cookie.setSub("igoogimi", "c3", createString("Column3"), {expires: date});
}
Notice that the method createString creates the subcookies values by looking for all children of the node with the matching column ID which pass the boolean test defined as the getNode method. In this method, we check to see if any of the children have IDs equal to the containers. If so, then those children ( these are nodes ) are returned. From those children, a string consisting of IDs in the order of their appearance in the DOM is created.
We set the igoogimi cookie when the unload event is fired. This occurs when we navigate to another page, close the browser, etc. This ensures that the cookie is always set.
When we read the cookie, a number of things happen.
The entire page is hidden through CSS ( the body's display is set to "none" ). We do this because the default layout is always there. We don't want it to appear and then be replaced by the layout found in the cookie.
Once we've determined whether the cookie exists, we remove all the nodes while keeping a reference to them. Then, we'll add them back based on the order that they're found in the igoogimi cookie --
var containerRef = [];
var node;
// BEGIN :: Removing the nodes
var cArray1 = c1.split(",");
var len = cArray1.length;
for(var i=0;i<len;i++){
node = document.getElementById(cArray1[i]);
node?containerRef[cArray1[i]] = node.parentNode.removeChild(node):"";
}
var cArray2 = c2.split(",");
len = cArray2.length;
for(var i=0;i<len;i++){
node = document.getElementById(cArray2[i]);
node?containerRef[cArray2[i]] = node.parentNode.removeChild(node):"";
}
var cArray3 = c3.split(",");
len = cArray3.length;
for(var i=0;i<len;i++){
node = document.getElementById(cArray3[i]);
node?containerRef[cArray3[i]] = node.parentNode.removeChild(node):"";
}
// END :: Removing the nodes
// BEGIN :: Adding the nodes
len = cArray1.length;
var col = document.getElementById("Column1");
var tmpCR;
for(var i=0;i<len;i++){
tmpCR = containerRef[cArray1[i]];
tmpCR?col.appendChild(tmpCR):"";
}
len = cArray2.length;
var col = document.getElementById("Column2");
for(var i=0;i<len;i++){
tmpCR = containerRef[cArray2[i]];
tmpCR?col.appendChild(tmpCR):"";
}
len = cArray3.length;
var col = document.getElementById("Column3");
for(var i=0;i<len;i++){
tmpCR = containerRef[cArray3[i]];
tmpCR?col.appendChild(tmpCR):"";
}
// END :: Adding the nodes
Keep in mind that we're passing through the DOM twice -- once for removal and another for insertion. So, it's not terribly efficient. Note that the removal and the insertions dynamically update the DOM and if we didn't hide the body, then the page would be jumping all over the place ( this is known as reflow where DOM manipulations are done when rendering is completed ). Once the last node has been added, we set the body's display to "block" and all the containers appear.
You can see our example here. To review the code, simply view the source.
Feel free to use and make it better.
Have fun!