1 // Layout container to handle one container with lm_left, lm_right, lm_top, lm_bottom, and lm_center
  2 rio.LayoutContainer = Class.create({
  3   initialize: function(root) {   
  4     this.parent = $(root.parentNode); 
  5     root.setStyle("padding:0; margin:0; border:0"); 
  6     // Pre-compute paddings
  7     $w("top left right bottom").each(function(key) { 
  8       this.parent[key] = this.padding(this.parent, key);
  9     }.bind(this));
 10     
 11     // Init arrays
 12     $w("lm_top lm_left lm_right lm_bottom lm_center").each(function(key) {
 13       this[key] = [];
 14     }.bind(this));
 15     
 16     root.childElements().each(function(element) {
 17       element.style.position = "absolute";
 18       element.paddingWidth   = this.fullPadding(element, "left") + this.fullPadding(element, "right");
 19       element.paddingHeight  = this.fullPadding(element, "top") + this.fullPadding(element, "bottom");
 20       element.marginWidth    = this.margin(element, "left") + this.margin(element, "right");
 21       element.marginHeight   = this.margin(element, "top") + this.margin(element, "bottom");
 22       
 23       if (element.hasClassName("lm_top")) {
 24         this.lm_top.push(element);
 25       } else if (element.hasClassName("lm_left")) {
 26         this.lm_left.push(element);  
 27       } else if (element.hasClassName("lm_right")) {
 28         this.lm_right.unshift(element);
 29       } else if (element.hasClassName("lm_bottom")) {
 30         this.lm_bottom.unshift(element);  
 31       } else if (element.hasClassName("lm_center")) {
 32         if (this.lm_center.length > 0) {
 33           throw("Only one lm_center per lm_container");
 34 		}
 35         this.lm_center.push(element);
 36       }
 37     }.bind(this));
 38   },
 39   
 40   updateSize: function() {      
 41     var d = this.parent.getDimensions();
 42     var w = d.width - this.parent.left - this.border(this.parent, "left") - this.border(this.parent, "right");
 43     var h = d.height - this.parent.top - this.parent.bottom  - this.border(this.parent, "top") - this.border(this.parent, "bottom");
 44     var that = this; // To avoid too many binds
 45    
 46     // Set position and size of all top elements  
 47     var top = this.parent.top;     
 48     this.lm_top.each(function(element) {   
 49       var s = element.style;   
 50       that.setPositivePxValue(s, 'width', w - element.paddingWidth);
 51       s.top = top + "px";
 52       top += element.getHeight() + element.marginHeight;
 53     });
 54     h -= top - this.parent.top;
 55     
 56     // Set position and size of all bottom elements
 57     var bottom = this.parent.bottom;
 58     this.lm_bottom.each(function(element) { 
 59       var s = element.style;   
 60       that.setPositivePxValue(s, 'width', w - element.paddingWidth);
 61       s.bottom = bottom + "px";
 62       bottom += element.getHeight() + element.marginHeight;
 63     });
 64     h -= bottom - this.parent.bottom;
 65      
 66     // Set position and size of all left elements
 67     var left = this.parent.left;          
 68     this.lm_left.each(function(element) {
 69       var s = element.style;  
 70       that.setPositivePxValue(s, 'height', h - element.paddingHeight);
 71       s.top  = top + "px";  
 72       s.left = left + "px";  
 73       left += element.getWidth() + element.marginWidth;
 74     });
 75     w -= left;
 76     
 77     // Set position and size of all right elements
 78     var right = this.parent.right;
 79     this.lm_right.each(function(element) {
 80       var s = element.style;
 81       that.setPositivePxValue(s, 'height', h - element.paddingHeight);
 82       s.top   = top + "px";  
 83       s.right = right + "px";  
 84       right += element.getWidth() + element.marginWidth;
 85     });
 86     w -= right;
 87      
 88     // Set position and size of all center elements
 89     // Only one center for this version
 90     var center = this.lm_center.first();
 91     var s = center.style;
 92     s.top  = top + "px"; 
 93     s.left = left + "px";  
 94     this.setPositivePxValue(s, 'width', w - center.paddingWidth);
 95     this.setPositivePxValue(s, 'height', h - center.paddingHeight);
 96   },
 97      
 98   // Private functions
 99   fullPadding: function(element, s) {   
100     return this.padding(element, s) + this.border(element, s) + this.margin(element, s);
101   },
102 
103   border: function(element, s) {   
104     var border = parseInt(element.getStyle("border-" + s + "-width") || 0, 10);
105     if (isNaN(border)) { // Test for IE!!
106       border = 0;
107 	}
108     return border;
109   },
110 
111   padding: function(element, s) {   
112     var padding = parseInt(element.getStyle("padding-" + s) || 0, 10);
113     if (isNaN(padding)) {   // Test for IE!!
114        padding = 0;
115 	}
116     return padding;
117   },
118 
119   margin: function(element, s) {   
120     var margin = parseInt(element.getStyle("margin-" + s) || 0, 10);
121     if (isNaN(margin)) {  // Test for IE!!
122        margin = 0;
123 	}
124     return margin;
125   },
126   
127   setPositivePxValue:function(objet, key, value) {
128     objet[key] =  (value > 0 ? value : 0) + "px";
129   }
130 });
131                  
132 // Layout manager: handles N layout container
133 rio.LayoutManager = Class.create({
134   initialize: function(root) {
135     this.root = root || document.body;
136     this.init();
137     Event.observe(window, "resize", this.resize.bind(this));
138   },
139   
140   reset: function() {
141     this.init.bind(this).defer();
142   }, 
143   
144   add: function(root) {       
145     this.addElement.bind(this, root, true).defer();
146   },
147   
148   // Private functions
149   init: function() {
150     this.containers = [];
151     this.addElement(this.root);  
152     this.resize();    
153   },
154   
155   resize: function() {
156    	this.containers.invoke("updateSize"); 
157   },
158   
159   addElement: function(element, doResize) {
160     $(element).getElementsBySelector(".lm_container").each(function(element) {
161       this.containers.push(new rio.LayoutContainer(element));
162     }.bind(this));
163     if (doResize) {
164       this.resize();
165 	}
166   }
167 });
168