cleaned up tabs
[plewww.git] / planetlab / minitabs / minitabs.js
1 /*
2  
3   Animated miniTabs by frequency decoder (http://www.frequency-decoder.com/)
4  
5   Based on an idea by Rob L Glazebrook (http://www.rootarcana.com/test/smartmini/) itself
6   derived from the original idea of Stephen Clark (http://www.sgclark.com/sandbox/minislide/)
7  
8   Adjusted by Thierry Parmentelat -- INRIA - uses only forms rather than <a> tags, for supporting http-POST
9   
10   $Id$
11
12 */
13
14 /* I'm done with this - write it ourselves - don't care about perfs so much anyway */
15 /* define getElementsByClassName on Element if missing */
16 function getElementsByClassName (elt,cls) {
17   try {
18     var retval= elt.getElementsByClassName(cls);
19     return retval;
20     } catch (err) {
21     var retVal = new Array();
22     var elements = elt.getElementsByTagName("*");
23     for (var i = 0; i < elements.length; i++) {
24       var element = elements[i];
25       var classes = element.className.split(" ");
26       for (var c = 0; c < classes.length; c++) 
27         if (classes[c] == cls) 
28           retVal.push(elements[i]);
29     }
30     return retVal;
31   }
32 }
33
34 var miniTab = {
35  currentTab:     0,
36  activeTab:      0,
37  destX:          0,
38  destW:          0,
39  t:              0,
40  b:              0,
41  c:              0,
42  d:              20,
43  animInterval:   null,
44  sliderObj:      null,
45  aHeight:        0,
46  ul:             [],
47  liArr:          [],
48  inputArr:       [],
49         
50  init: function() {
51
52     miniTab.ul          = document.getElementById("minitabs-list");
53     miniTab.liArr       = miniTab.ul.getElementsByTagName("li");
54     // Thierry: the original impl. relied on <a> links rather than forms 
55     // we use <input>s and there might be hidden ones, so use a class marker instead
56     miniTab.inputArr        = getElementsByClassName(miniTab.ul,"minitabs-submit");
57  
58     for(var i = 0, li; li = miniTab.liArr[i]; i++) {
59       li.onmouseover = miniTab.inputArr[i].onfocus = function(e) {
60         var pos = 0;
61         var elem = this;
62         /* some browsers - firefox - somehow trigger this on <input> */
63         if (this.nodeName != "LI") return;
64         /* move up until we find the 'LI' tag */
65         while(elem.previousSibling) {
66           elem = elem.previousSibling;
67           if(elem.tagName && elem.tagName == "LI") pos++;
68  
69         }
70         miniTab.initSlide(pos,true);
71       }
72     }
73  
74     miniTab.ul.onmouseout = function(e) {
75       miniTab.initSlide(miniTab.currentTab,true);
76       miniTab.setActive (miniTab.activeTab,false);
77     };
78  
79     for(var i = 0, input; input = miniTab.inputArr[i]; i++) {
80       if(input.className.search("active") != -1) {
81         miniTab.activeTab = miniTab.currentTab = i;
82       }
83       /*input.style.borderBottom  = "0px";*/
84       /*input.style.paddingBottom = "6px";*/
85     }
86  
87     miniTab.slideObj                = miniTab.ul.parentNode.appendChild(document.createElement("div"));
88     miniTab.slideObj.appendChild(document.createTextNode(String.fromCharCode(160)));
89     miniTab.slideObj.id             = "minitabs-sliding";
90
91     miniTab.setTop();
92
93     miniTab.slideObj.style.left     = (miniTab.ul.offsetLeft + miniTab.liArr[miniTab.activeTab].offsetLeft + 
94                                        miniTab.inputArr[miniTab.activeTab].offsetLeft) + "px";
95     miniTab.slideObj.style.width    = miniTab.inputArr[miniTab.activeTab].offsetWidth + "px";
96     miniTab.aHeight                 = (miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop + 
97                                        miniTab.inputArr[miniTab.activeTab].offsetTop);
98  
99     miniTab.initSlide(miniTab.activeTab, true);
100  
101     var intervalMethod = function() { miniTab.slideIt(); }
102     miniTab.animInterval = setInterval(intervalMethod,10);
103   },
104  
105  cleanUp: function() {
106     clearInterval(miniTab.animInterval);
107     miniTab.animInterval = null;
108   },
109  
110  initSlide: function(pos, force) {
111     if(!force && pos == miniTab.activeTab) return;
112     miniTab.setActive (miniTab.activeTab,false);
113     miniTab.activeTab = pos;
114     miniTab.setActive (miniTab.activeTab,true);
115     miniTab.initAnim();
116   },
117  
118  setActive: function (pos,active) {
119     var input=getElementsByClassName(miniTab.liArr[pos],"minitabs-submit")[0];
120     var cn=input.className;
121     cn=cn.replace(" active","");
122     if (active) cn += " active";
123     input.className=cn;
124   },
125  
126  initAnim: function() {
127     /* search for the input with type != hidden */
128     var input=getElementsByClassName(miniTab.liArr[miniTab.activeTab],"minitabs-submit")[0];
129     miniTab.destX = parseInt(miniTab.liArr[miniTab.activeTab].offsetLeft + input.offsetLeft + miniTab.ul.offsetLeft);
130     miniTab.destW = parseInt(input.offsetWidth);
131     miniTab.t = 0;
132     miniTab.b = miniTab.slideObj.offsetLeft;
133     miniTab.c = miniTab.destX - miniTab.b;
134  
135     miniTab.bW = miniTab.slideObj.offsetWidth;
136     miniTab.cW = miniTab.destW - miniTab.bW;
137  
138     miniTab.setTop();
139   },
140  
141  setTop: function () {
142     var delta=0;
143     /* up 5px for firefox */
144     if (navigator.userAgent.match(/Firefox/)) delta=-5; 
145     miniTab.slideObj.style.top  = (miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop 
146                                    + miniTab.inputArr[miniTab.activeTab].offsetTop + delta ) + "px";
147
148   },
149
150  slideIt:function() {
151  
152     // Has the browser text size changed?
153     if(miniTab.aHeight != miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop + miniTab.inputArr[miniTab.activeTab].offsetTop) {
154       miniTab.initAnim();
155       miniTab.aHeight = miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop + miniTab.inputArr[miniTab.activeTab].offsetTop
156     };
157  
158     if(miniTab.t++ < miniTab.d) {
159       var x = miniTab.animate(miniTab.t,miniTab.b,miniTab.c,miniTab.d);
160       var w = miniTab.animate(miniTab.t,miniTab.bW,miniTab.cW,miniTab.d);
161  
162       miniTab.slideObj.style.left = parseInt(x) + "px";
163       miniTab.slideObj.style.width = parseInt(w) + "px";
164     } else {
165       miniTab.slideObj.style.left = miniTab.destX + "px";
166       miniTab.slideObj.style.width = miniTab.destW +"px";
167     }
168   },
169  
170  animate: function(t,b,c,d) {
171     if ((t/=d/2) < 1) return c/2*t*t + b;
172     return -c/2 * ((--t)*(t-2) - 1) + b;
173   },
174
175  submit: function (message) {
176     /* save activeTab before confirmation; some browsers - firefox - send mouseout during confirm .. */
177     var submitTab = this.activeTab;
178     /* ask for confirmation if message is not empty */
179     if (message && ! confirm (message) ) return;
180     this.inputArr[submitTab].parentNode.parentNode.submit();
181   }
182 }
183  
184 window.onload = miniTab.init;
185 window.onunload = miniTab.cleanUp;
186