update
[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.slideObj = null;
28   this.aHeight = 0;
29 }
30
31 linetabs.prototype.init = function (div) {
32   this.ul      = div.down('ul');
33   /* the array of <li>'s */
34   this.li_s    = this.ul.select('li');
35   /* the array of active <input>'s - without any hidden one */
36   this.input_s = this.ul.select('input.linetabs-submit');
37   
38   /* attach event handlers */
39   this.li_s.each ( function (li) { 
40       li.observe ('mouseover', function(event) {
41           var elem = event.element();
42           /* make sure we're on the 'li' element */
43           if ( ! elem.match('li') ) elem=elem.up('li');
44           /* determine current position */
45           var pos = 0;
46           while(elem.previousSibling) {
47             elem = elem.previousSibling;
48             if (elem.tagName && elem.tagName == "LI") pos++;
49           }
50           linetabs_namespace.the_linetabs(elem).initSlide(pos,true);
51         } )
52         } );
53   
54   this.ul.observe('mouseout', function (event) {
55       var mt = linetabs_namespace.the_linetabs(event.element());
56       mt.initSlide(mt.currentTab,true);
57       mt.setActive (mt.activeTab,false);
58     });
59   
60   /* set active and current, default is index 0, set 'active' class otherwise */
61   this.input_s.each ( function (input) {
62       if (input.hasClassName("active")) this.activeTab = this.currentTab = i;
63     });
64   
65   /* create slice object */
66   this.slideObj    = this.ul.parentNode.appendChild(document.createElement("div"));
67   this.slideObj.appendChild(document.createTextNode(String.fromCharCode(160)));
68   this.slideObj.id = "linetabs-sliding";
69   
70     /* position it */
71   this.setSlidingTop();
72   this.slideObj.style.left     = (this.ul.offsetLeft + this.li_s[this.activeTab].offsetLeft + 
73                                   this.input_s[this.activeTab].offsetLeft) + "px";
74   this.slideObj.style.width    = this.input_s[this.activeTab].offsetWidth + "px";
75   this.aHeight                 = (this.ul.offsetTop + this.li_s[this.activeTab].offsetTop + 
76                                   this.input_s[this.activeTab].offsetTop);
77   
78   this.initSlide(this.activeTab, true);
79     
80 };
81
82 linetabs.prototype.initSlide = function (pos, force) {
83   
84   if(!force && pos == this.activeTab) return;
85   this.setActive (this.activeTab,false);
86   this.activeTab = pos;
87   this.setActive (this.activeTab,true);
88   this.initAnim();
89 };
90  
91 linetabs.prototype.setActive = function (pos,active) {
92   var input=this.li_s[pos].select('input.linetabs-submit')[0];
93   if (active)
94     input.addClassName('active');
95   else
96     input.removeClassName('active');
97 };
98   
99 linetabs.prototype.setSlidingTop = function () {
100   var delta=0;
101   /* up 5px for firefox */
102   /*window.console.log('agent=' + navigator.userAgent);*/
103   if (navigator.userAgent.match(/Firefox/)) delta=-5; 
104   this.slideObj.style.top  = (this.ul.offsetTop + this.li_s[this.activeTab].offsetTop 
105                               + this.input_s[this.activeTab].offsetTop + delta ) + "px";
106 };
107   
108 linetabs.prototype.initAnim = function() {
109   /* search for the input with type != hidden */
110   var input=this.li_s[this.activeTab].select('input.linetabs-submit')[0];
111   this.destX = parseInt(this.li_s[this.activeTab].offsetLeft + input.offsetLeft 
112                         + this.ul.offsetLeft);
113   this.destW = parseInt(input.offsetWidth);
114   this.t = 0;
115   this.b = this.slideObj.offsetLeft;
116   this.c = this.destX - this.b;
117   
118   this.bW = this.slideObj.offsetWidth;
119   this.cW = this.destW - this.bW;
120   
121   this.setSlidingTop();
122 };
123   
124 linetabs.prototype.slideIt = function() {
125   
126   // Has the browser text size changed?
127   var active_li = this.li_s[this.activeTab];
128   var active_input = this.input_s[this.activeTab];
129   if (this.aHeight != this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop) {
130     this.initAnim();
131     this.aHeight = this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop;
132   }
133   
134   
135   if (this.t++ < this.d) {
136     var x = this.animate(this.t,this.b,this.c,this.d);
137     var w = this.animate(this.t,this.bW,this.cW,this.d);
138     
139     this.slideObj.style.left = parseInt(x) + "px";
140     this.slideObj.style.width = parseInt(w) + "px";
141   } else {
142     this.slideObj.style.left = this.destX + "px";
143     this.slideObj.style.width = this.destW +"px";
144   }
145 };
146   
147 linetabs.prototype.animate = function(t,b,c,d) {
148   if ((t/=d/2) < 1) return c/2*t*t + b;
149   return -c/2 * ((--t)*(t-2) - 1) + b;
150 };
151
152 linetabs.prototype.submit = function (message) {
153   /* save activeTab before confirmation; some browsers - firefox - send mouseout during confirm .. */
154   var submitTab = this.activeTab;
155   /* ask for confirmation if message is not empty */
156   if (message && ! confirm (message) ) return;
157
158   /* get the form and trigger */
159   this.li_s[submitTab].down('form').submit();
160   
161 }
162   
163 // globals
164 var linetabs_namespace = {
165  init: function () {
166     $$('div.linetabs').each (function (div) {   
167         /* create instance and attach it to the <div> element */
168         div.linetabs = new linetabs ();
169         div.linetabs.init(div);
170       } ) ;
171     
172     var intervalMethod = function () {
173       $$('div.linetabs').each (function (div) {
174           linetabs_namespace.the_linetabs(div).slideIt();
175         } ) ;
176     } ;
177     linetabs_namespace.animInterval = setInterval(intervalMethod,10);
178   },
179  
180  cleanUp: function() {
181     clearInterval(linetabs_namespace.animInterval);
182     linetabs_namespace.animInterval = null;
183   },
184  
185  resize: function (e) {
186     $$('div.linetabs').each ( function (div) { 
187         var mt = div.linetabs; 
188         mt.initSlide(mt.activeTab,true);
189       } );
190   },
191
192  submit: function (id,message) {
193     $(id).linetabs.submit(message);
194   },
195
196  // find the enclosing linetabs object
197  the_linetabs: function (elem) {
198     if (elem.match('div.linetabs')) 
199       return elem.linetabs;
200     else 
201       return elem.up('div.linetabs').linetabs;
202   }
203  
204 };
205  
206 Event.observe(window, 'load',linetabs_namespace.init);
207 Event.observe(window, 'unload', linetabs_namespace.cleanUp);
208 Event.observe(window, 'resize', linetabs_namespace.resize);