On my current Monorail project I am using the Holy Grail layout I mentioned here . The javascript I modified for this worked just fine but I wanted to be able to keep an element in the bottom right corner of almost every page showing a dynamic contact email.
My first thought was to place a negative margin-top on the footer, nudging the floated element into the content area...kind of an illusion for placement. The problem is, the script places the columns over the area even with z-indices set.
So, I needed to attach an event to my CSSColumns javascript so that I could use the calculated 'height' to apply to the 'top' style attribute of my absolutely positioned element (nested in a relative element).
Here's the content markup snippet:
<!--BEGIN #content -->
<div id="content">
<!--BEGIN #c1-->
<div id="c1" class="column">
${ChildOutput}
<!--END #c1-->
</div>
<!--BEGIN #c2-->
<div id="c2" class="column">
${?imageboxout}
${?leftcontent}
<!--END #c2-->
</div>
<!--BEGIN #c3-->
<div id="c3" class="column"><!--position:relative;-->
${?rightcontent}
<div id="bottom-right"><!--position:absolute;-->
${?bottomright}
</div>
<!--END #c3-->
</div>
<!--END #content-->
One interesting problem: I was using variable length arguments to pass to my object accepting any number of element ids to modify at pageLoad. But I wanted to use an inline {option:value} syntax. How will this work since I am not passing in a 'options' parameter? The code below shows my solution. Works great and is extensible for future options (unlike the previous incarnation):
/*Adapted from http://www.thewatchmakerproject.com/journal/308/equal-height-boxes-with-javascript
fixing IE7 compatibility issues and using prototype.js loaded first*/
/*COMMON USAGE:
In the head element...
<script type="text/javascript">
var setBottomRightDiv = function(maxHeight){
var h = (maxHeight - 60).toString();
$('bottom-right').setStyle({'top': h + "px"});
};
var col = new CSSColumns('content','c1','c2','c3',{onColumnsSet:setBottomRightDiv});
FastInit.addOnLoad(function() { col.equalise(); });
</script>
>>Where 'bottom-right' might be an element you want to position based on the maxHeight calculation.
>>'content','c1','c2','c3' are column (div) container ids. Any number of column ids may be passed in.
>>The last argument may be for 'options'. Here, the onColumnsSet delegate to fire upon setting.
>>attach CSSColumns 'equalise' method to the page's onload event. (Here, using FastInit).
*/
CSSColumns = Class.create();
Object.extend(CSSColumns.prototype,{
maxHeight: 0,
elIds: new Array(),
els: new Array(),
initialize: function(){
for(var i=0;i<arguments.length;i++)
{
if(!(arguments[i] instanceof Object)){
this.elIds.push(arguments[i]);
}
else{
this.options = {
onColumnsSet: Prototype.emptyFunction
};
Object.extend(this.options,arguments[i] || {});
}
}
},
setEls: function(){
for (var i=0;i<this.elIds.length;i++) if (!$(this.elIds[i])) return;
for(var i=0;i<this.elIds.length;i++)
{
this.els.push($(this.elIds[i]));
}
},
setOptions: function(options){
},
equalise: function(){
this.setEls();
this.maxHeight = this.calcMaxHeight();
for(var i=0;i<this.els.length;i++){
this.els[i].style.height = this.maxHeight + "px";
}
this.notify('onColumnsSet',this.maxHeight);
},
calcMaxHeight: function(){
var h = 0;
for(var i=0;i<this.els.length;i++)
{
if(this.els[i].getHeight()>h)
{
h=this.els[i].getHeight();
}
}
return h;
},
notify: function(event_name){
if(this.options){
(this.options[event_name])
return [this.options[event_name].apply(this.options[event_name],$A(arguments).slice(1))];
}
}
});
if(typeof(Object.Event) != 'undefined')
Object.Event.extend(CSSColumns);
Now my element ('bottom-right') is found just where it should be on every page!