cleanup again - open 'node table layout' only the first time
[plewww.git] / plekit / linetabs / linetabs.js
1 /*
2   $Id$
3
4   Animated linetabs by frequency decoder (http://www.frequency-decoder.com/)
5
6   Based on an idea by Rob L Glazebrook (http://www.rootarcana.com/test/smartmini/) itself
7   derived from the original idea of Stephen Clark (http://www.sgclark.com/sandbox/minislide/)
8
9   Rewritten by Thierry Parmentelat -- INRIA
10   support http-POST
11   support multiple instances
12   uses prototype.js
13
14 */
15
16 /* class */
17 function linetabs () {
18   this.currentTab = 0;
19   this.activeTab = 0;
20   this.destX = 0;
21   this.destW = 0;
22   this.t = 0;
23   this.b = 0;
24   this.c = 0;
25   this.d = 20;
26   this.animInterval = null;
27   this.elem_div_linetabs = null;
28   this.slideObj = null;
29   this.aHeight = 0;
30 }
31
32 linetabs.prototype.init = function (div) {
33   this.ul      = div.down('ul');
34   /* the array of <li>'s */
35   this.li_s    = this.ul.select('li');
36   /* the array of active <input>'s - without any hidden one */
37   this.input_s = this.ul.select('input.linetabs-submit');
38
39   /* attach event handlers */
40   this.li_s.each ( function (li) {
41       li.observe ('mouseover', function(event) {
42           var elem = event.element();
43           /* make sure we're on the 'li' element */
44           if ( ! elem.match('li') ) elem=elem.up('li');
45           /* determine current position */
46           var pos = 0;
47           while(elem.previousSibling) {
48             elem = elem.previousSibling;
49             if (elem.tagName && elem.tagName == "LI") pos++;
50           }
51           linetabs_namespace.the_linetabs(elem).initSlide(pos,true);
52         } );
53    } );
54
55   this.ul.observe('mouseout', function (event) {
56       var mt = linetabs_namespace.the_linetabs(event.element());
57       mt.initSlide(mt.currentTab,true);
58       mt.setActive (mt.activeTab,false);
59     });
60
61   /* create slice object */
62   this.slideObj    = this.ul.parentNode.appendChild(document.createElement("div"));
63   this.slideObj.appendChild(document.createTextNode(String.fromCharCode(160)));
64   this.slideObj.id = "linetabs-sliding";
65
66     /* position it */
67   this.setSlidingTop();
68   this.slideObj.style.left     = (this.ul.offsetLeft + this.li_s[this.activeTab].offsetLeft +
69                                   this.input_s[this.activeTab].offsetLeft) + "px";
70   this.slideObj.style.width    = this.input_s[this.activeTab].offsetWidth + "px";
71   this.aHeight                 = (this.ul.offsetTop + this.li_s[this.activeTab].offsetTop +
72                                   this.input_s[this.activeTab].offsetTop);
73
74   my_object = this;
75   /* set active and current, default is index 0, set 'active' class otherwise */
76   this.input_s.each ( function (input, index) {
77       if (input.hasClassName("active")) my_object.activeTab = my_object.currentTab = index;
78   });
79
80
81   this.initSlide(this.activeTab, true);
82
83 };
84
85 linetabs.prototype.initSlide = function (pos, force) {
86
87   if(!force && pos == this.activeTab) return;
88   this.setActive (this.activeTab,false);
89   this.activeTab = pos;
90   this.setActive (this.activeTab,true);
91   this.initAnim();
92 };
93
94 linetabs.prototype.setActive = function (pos,active) {
95   var input=this.li_s[pos].select('input.linetabs-submit')[0];
96   if (active)
97     input.addClassName('active');
98   else
99     input.removeClassName('active');
100 };
101
102 linetabs.prototype.setSlidingTop = function () {
103   var delta=0;
104   /* up 5px for firefox */
105   /*window.console.log('agent=' + navigator.userAgent);*/
106   if (navigator.userAgent.match(/Firefox/)) delta=-5;
107   this.slideObj.style.top  = (this.ul.offsetTop + this.li_s[this.activeTab].offsetTop
108                               + this.input_s[this.activeTab].offsetTop + delta ) + "px";
109 };
110
111 linetabs.prototype.initAnim = function() {
112   /* search for the input with type != hidden */
113   var input=this.li_s[this.activeTab].select('input.linetabs-submit')[0];
114   this.destX = parseInt(this.li_s[this.activeTab].offsetLeft + input.offsetLeft
115                         + this.ul.offsetLeft);
116   this.destW = parseInt(input.offsetWidth);
117   this.t = 0;
118   this.b = this.slideObj.offsetLeft;
119   this.c = this.destX - this.b;
120
121   this.bW = this.slideObj.offsetWidth;
122   this.cW = this.destW - this.bW;
123
124   this.setSlidingTop();
125 };
126
127 linetabs.prototype.slideIt = function() {
128
129   // Has the browser text size changed?
130   var active_li = this.li_s[this.activeTab];
131   var active_input = this.input_s[this.activeTab];
132   if (this.aHeight != this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop) {
133     this.initAnim();
134     this.aHeight = this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop;
135   }
136
137
138   if (this.t++ < this.d) {
139     var x = this.animate(this.t,this.b,this.c,this.d);
140     var w = this.animate(this.t,this.bW,this.cW,this.d);
141
142     this.slideObj.style.left = parseInt(x) + "px";
143     this.slideObj.style.width = parseInt(w) + "px";
144   } else {
145     this.slideObj.style.left = this.destX + "px";
146     this.slideObj.style.width = this.destW +"px";
147   }
148 };
149
150 linetabs.prototype.animate = function(t,b,c,d) {
151   if ((t/=d/2) < 1) return c/2*t*t + b;
152   return -c/2 * ((--t)*(t-2) - 1) + b;
153 };
154
155 linetabs.prototype.submit = function (message) {
156   /* save activeTab before confirmation; some browsers - firefox - send mouseout during confirm .. */
157   var submitTab = this.activeTab;
158   /* ask for confirmation if message is not empty */
159   if (message && ! confirm (message) ) return;
160
161   /* get the form and trigger */
162   this.li_s[submitTab].down('form').submit();
163
164 }
165
166 // globals
167 var linetabs_namespace = {
168  init: function () {
169     // just give it a little time to load everything.
170     setTimeout('linetabs_namespace.lazyInit()', 1000);
171  },
172
173  lazyInit: function() {
174     linetabs_namespace.elem_div_linetabs = $$('div.linetabs');
175
176     Event.observe('linetabs',
177                   'mouseover',
178                   function() {
179                       linetabs_namespace.elem_div_linetabs = $$('div.linetabs');
180                   });
181
182     linetabs_namespace.elem_div_linetabs.each (function (div) {
183         /* create instance and attach it to the <div> element */
184         div.linetabs = new linetabs ();
185         div.linetabs.init(div);
186       } ) ;
187
188     var intervalMethod = function () {
189         linetabs_namespace.elem_div_linetabs.each (function (div) {
190                 linetabs_namespace.the_linetabs(div).slideIt();
191             } ) ;
192     } ;
193     linetabs_namespace.animInterval = setInterval(intervalMethod,10);
194   },
195
196  cleanUp: function() {
197     clearInterval(linetabs_namespace.animInterval);
198     linetabs_namespace.animInterval = null;
199     linetabs_namespace.elem_div_linetabs = null;
200   },
201
202  resize: function (e) {
203     $$('div.linetabs').each ( function (div) {
204         var mt = div.linetabs;
205         mt.initSlide(mt.activeTab,true);
206       } );
207   },
208
209  submit: function (id,message) {
210     $(id).linetabs.submit(message);
211   },
212
213  // find the enclosing linetabs object
214  the_linetabs: function (elem) {
215     if (elem.match('div.linetabs'))
216       return elem.linetabs;
217     else
218       return elem.up('div.linetabs').linetabs;
219   }
220
221 };
222
223 Event.observe(window, 'load', linetabs_namespace.init);
224 Event.observe(window, 'unload', linetabs_namespace.cleanUp);
225 Event.observe(window, 'resize', linetabs_namespace.resize);