4 Animated linetabs by frequency decoder (http://www.frequency-decoder.com/)
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/)
9 Rewritten by Thierry Parmentelat -- INRIA
11 support multiple instances
17 function linetabs () {
26 this.animInterval = null;
27 this.elem_div_linetabs = null;
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');
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 */
47 while(elem.previousSibling) {
48 elem = elem.previousSibling;
49 if (elem.tagName && elem.tagName == "LI") pos++;
51 linetabs_namespace.the_linetabs(elem).initSlide(pos,true);
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);
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";
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);
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;
81 this.initSlide(this.activeTab, true);
85 linetabs.prototype.initSlide = function (pos, force) {
87 if(!force && pos == this.activeTab) return;
88 this.setActive (this.activeTab,false);
90 this.setActive (this.activeTab,true);
94 linetabs.prototype.setActive = function (pos,active) {
95 var input=this.li_s[pos].select('input.linetabs-submit')[0];
97 input.addClassName('active');
99 input.removeClassName('active');
102 linetabs.prototype.setSlidingTop = function () {
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";
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);
118 this.b = this.slideObj.offsetLeft;
119 this.c = this.destX - this.b;
121 this.bW = this.slideObj.offsetWidth;
122 this.cW = this.destW - this.bW;
124 this.setSlidingTop();
127 linetabs.prototype.slideIt = function() {
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) {
134 this.aHeight = this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop;
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);
142 this.slideObj.style.left = parseInt(x) + "px";
143 this.slideObj.style.width = parseInt(w) + "px";
145 this.slideObj.style.left = this.destX + "px";
146 this.slideObj.style.width = this.destW +"px";
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;
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;
161 /* get the form and trigger */
162 this.li_s[submitTab].down('form').submit();
167 var linetabs_namespace = {
169 // just give it a little time to load everything.
170 setTimeout('linetabs_namespace.lazyInit()', 1000);
173 lazyInit: function() {
174 linetabs_namespace.elem_div_linetabs = $$('div.linetabs');
176 Event.observe('linetabs',
179 linetabs_namespace.elem_div_linetabs = $$('div.linetabs');
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);
188 var intervalMethod = function () {
189 linetabs_namespace.elem_div_linetabs.each (function (div) {
190 linetabs_namespace.the_linetabs(div).slideIt();
193 linetabs_namespace.animInterval = setInterval(intervalMethod,10);
196 cleanUp: function() {
197 clearInterval(linetabs_namespace.animInterval);
198 linetabs_namespace.animInterval = null;
199 linetabs_namespace.elem_div_linetabs = null;
202 resize: function (e) {
203 $$('div.linetabs').each ( function (div) {
204 var mt = div.linetabs;
205 mt.initSlide(mt.activeTab,true);
209 submit: function (id,message) {
210 $(id).linetabs.submit(message);
213 // find the enclosing linetabs object
214 the_linetabs: function (elem) {
215 if (elem.match('div.linetabs'))
216 return elem.linetabs;
218 return elem.up('div.linetabs').linetabs;
223 Event.observe(window, 'load', linetabs_namespace.init);
224 Event.observe(window, 'unload', linetabs_namespace.cleanUp);
225 Event.observe(window, 'resize', linetabs_namespace.resize);