several instances supported (no globals)
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 15 Feb 2009 15:29:43 +0000 (15:29 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 15 Feb 2009 15:29:43 +0000 (15:29 +0000)
planetlab/includes/plc_minitabs.php
planetlab/minitabs/minitabs.css
planetlab/minitabs/minitabs.js

index e681477..db8301d 100644 (file)
@@ -2,6 +2,7 @@
   // $Id$
 
 drupal_set_html_head('
+<script type="text/javascript" src="/planetlab/prototype/prototype.js"></script>
 <script type="text/javascript" src="/planetlab/minitabs/minitabs.js"></script>
 <link href="/planetlab/minitabs/minitabs.css" rel="stylesheet" type="text/css" />
 ');
@@ -25,9 +26,10 @@ drupal_set_html_head('
 //     (*) 'id' : assign given id to the <li> element
 
 // NOTE
-// values can also be set in the URL, e.g. ?var=value&foo=bar, even for POST'ing
+// (*) values can also be set in the URL, e.g. ?var=value&foo=bar, even for POST'ing
+// (*) several instances can appear on the same page but you need to give them different id's
 
-// examples
+// EXAMPLES
 // function my_tab () { return array('label'=>'Go to google','url'=>'http://google.com'); }
 // $tabs=array();
 // $tabs[] = my_tab();
@@ -41,10 +43,10 @@ drupal_set_html_head('
 //     (the form gets submitted whatever the confirmation....)
 // (*) you need to tune the image size, which is wrong, as the image should rather be bottom-aligned 
 
-function plc_tabs ($array) {
-  print '<div id="minitabs-container">';
-  print '<ul id="minitabs-list">';
-  print "\n";
+function plc_tabs ($array, $id=NULL) {
+  if (! $id) $id="minitabs";
+  print "<div id='$id' class='minitabs'>";
+  print "<ul>";
   foreach ($array as $label=>$todo) {
     // in case we have a simple string, rewrite it as an array
     if (is_string ($todo)) $todo=array('method'=>'GET','url'=>$todo);
@@ -53,7 +55,7 @@ function plc_tabs ($array) {
     $tracer="class=minitabs";
     if ($todo['id']) 
       $tracer .= " id=".$todo['id'];
-    printf ("<li %s>\n",$tracer);
+    print "<li $tracer>";
     // set default method
     if ( ! $todo['method'] ) $todo['method']='GET';
     // extract var=value settings from url if any
@@ -70,7 +72,7 @@ function plc_tabs ($array) {
     if ( ! $values) $values = array();
     if ($url_values) $values = array_merge($values,$url_values);
     if ( $values ) foreach ($values as $key=>$value) {
-       printf('<input class="minitabs-hidden" type=hidden name="%s" value="%s" />',$key,$value);
+       print "<input class='minitabs-hidden' type=hidden name='$key' value='$value' />";
       }
     $tracer="class=minitabs-submit";
     // image and its companions 'height' 
@@ -80,12 +82,13 @@ function plc_tabs ($array) {
     } else {
       $type='type=button value="' . $label . '"';
     }
-    printf('<span title="%s">',$todo['bubble']);
+    $bubble=$todo['bubble'];
+    print "<span title='$bubble'>";
     $message="";
     if ($todo['confirm']) $message=$todo['confirm'] . " ?";
-    printf('<input %s %s onclick=\'miniTab.submit("%s");\' />',$tracer,$type,$message);
-    printf('</span>',$todo['bubble']);
-    printf("</form></li>\n");
+    print "<input $tracer $type onclick='minitabs_namespace.submit(\"$id\",\"$message\")' />";
+    print "</span>";
+    print "</form></li>\n";
   }
   print '</ul>';
   print '</div>';
index 3ce302d..fe364ae 100644 (file)
@@ -1,12 +1,12 @@
 /* $Id$ */
 
-#minitabs-container {
+div.minitabs {
     padding: 20px;
     margin: 8px 0;
     width:80%;
     margin:8px auto;
 }
-#minitabs-list {
+div.minitabs>ul {
     width: 100%;
     float: left;
     font-size: small;  /* could be specified at a higher level */
@@ -29,7 +29,7 @@ input.minitabs-submit {
     /*padding-bottom: 6px;*/
     border-bottom: 0px;
 }    
-#minitabs-list li {
+div.minitabs>ul>li {
     float: left;
     margin: 0;
     padding: 0 8px 0 8px;
@@ -38,7 +38,7 @@ input.minitabs-submit {
     position:relative;
 }
 
-#minitabs-list input.minitabs-submit {
+div.minitabs>ul>li input.minitabs-submit {
     float: left;
     font-size: 85%;
     line-height: 20px;
@@ -49,7 +49,7 @@ input.minitabs-submit {
     color: #9c9;  
 }
 
-#minitabs-list input.active {
+div.minitabs>ul>li input.active {
     /* border-bottom: 4px solid #696; */
     /* padding-bottom: 2px; */
     /* color when mouse is on button */
index 0d29d53..e532e90 100644 (file)
 /*
+  $Id$
  
   Animated miniTabs by frequency decoder (http://www.frequency-decoder.com/)
  
   Based on an idea by Rob L Glazebrook (http://www.rootarcana.com/test/smartmini/) itself
   derived from the original idea of Stephen Clark (http://www.sgclark.com/sandbox/minislide/)
  
-  Adjusted by Thierry Parmentelat -- INRIA - uses only forms rather than <a> tags, for supporting http-POST
-  
-  $Id$
+  Rewritten by Thierry Parmentelat -- INRIA 
+  support http-POST
+  support multiple instances
+  uses prototype.js  
 
 */
 
-/* I'm done with this - write it ourselves - don't care about perfs so much anyway */
-/* define getElementsByClassName on Element if missing */
-function getElementsByClassName (elt,cls) {
-  try {
-    var retval= elt.getElementsByClassName(cls);
-    return retval;
-    } catch (err) {
-    var retVal = new Array();
-    var elements = elt.getElementsByTagName("*");
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      var classes = element.className.split(" ");
-      for (var c = 0; c < classes.length; c++) 
-       if (classes[c] == cls) 
-         retVal.push(elements[i]);
-    }
-    return retVal;
-  }
+/* class */
+function minitabs () {
+  this.currentTab = 0;
+  this.activeTab = 0;
+  this.destX = 0;
+  this.destW = 0;
+  this.t = 0;
+  this.b = 0;
+  this.c = 0;
+  this.d = 20;
+  this.animInterval = null;
+  this.slideObj = null;
+  this.aHeight = 0;
 }
 
-var miniTab = {
- currentTab:     0,
- activeTab:      0,
- destX:          0,
- destW:          0,
- t:              0,
- b:              0,
- c:              0,
- d:              20,
- animInterval:   null,
- sliderObj:      null,
- aHeight:        0,
- ul:             [],
- liArr:          [],
- inputArr:       [],
-        
- init: function() {
-
-    miniTab.ul          = document.getElementById("minitabs-list");
-    miniTab.liArr       = miniTab.ul.getElementsByTagName("li");
-    // Thierry: the original impl. relied on <a> links rather than forms 
-    // we use <input>s and there might be hidden ones, so use a class marker instead
-    miniTab.inputArr        = getElementsByClassName(miniTab.ul,"minitabs-submit");
-    for(var i = 0, li; li = miniTab.liArr[i]; i++) {
-      li.onmouseover = miniTab.inputArr[i].onfocus = function(e) {
-       var pos = 0;
-       var elem = this;
-       /* some browsers - firefox - somehow trigger this on <input> */
-       if (this.nodeName != "LI") return;
-       /* move up until we find the 'LI' tag */
-       while(elem.previousSibling) {
-         elem = elem.previousSibling;
-         if(elem.tagName && elem.tagName == "LI") pos++;
-       }
-       miniTab.initSlide(pos,true);
-      }
-    }
-    miniTab.ul.onmouseout = function(e) {
-      miniTab.initSlide(miniTab.currentTab,true);
-      miniTab.setActive (miniTab.activeTab,false);
-    };
-    window.onresize = function (e) {
-      miniTab.initSlide (miniTab.activeTab,true);
-    }
+minitabs.prototype.init = function (div) {
+  this.ul      = div.down('ul');
+  /* the array of <li>'s */
+  this.li_s    = this.ul.select('li');
+  /* the array of active <input>'s - without any hidden one */
+  this.input_s = this.ul.select('input.minitabs-submit');
+  
+  /* attach event handlers */
+  this.li_s.each ( function (li) { 
+      li.observe ('mouseover', function(event) {
+         var elem = event.element();
+         /* make sure we're on the 'li' element */
+         if ( ! elem.match('li') ) elem=elem.up('li');
+         /* determine current position */
+         var pos = 0;
+         while(elem.previousSibling) {
+           elem = elem.previousSibling;
+           if (elem.tagName && elem.tagName == "LI") pos++;
+         }
+         minitabs_namespace.the_minitabs(elem).initSlide(pos,true);
+       } )
+       } );
+  
+  this.ul.observe('mouseout', function (event) {
+      var mt = minitabs_namespace.the_minitabs(event.element());
+      mt.initSlide(mt.currentTab,true);
+      mt.setActive (mt.activeTab,false);
+    });
+  
+  /* set active and current, default is index 0, set 'active' class otherwise */
+  this.input_s.each ( function (input) {
+      if (input.hasClassName("active")) this.activeTab = this.currentTab = i;
+    });
+  
+  /* create slice object */
+  this.slideObj    = this.ul.parentNode.appendChild(document.createElement("div"));
+  this.slideObj.appendChild(document.createTextNode(String.fromCharCode(160)));
+  this.slideObj.id = "minitabs-sliding";
+  
+    /* position it */
+  this.setSlidingTop();
+  this.slideObj.style.left     = (this.ul.offsetLeft + this.li_s[this.activeTab].offsetLeft + 
+                                 this.input_s[this.activeTab].offsetLeft) + "px";
+  this.slideObj.style.width    = this.input_s[this.activeTab].offsetWidth + "px";
+  this.aHeight                 = (this.ul.offsetTop + this.li_s[this.activeTab].offsetTop + 
+                                 this.input_s[this.activeTab].offsetTop);
+  
+  this.initSlide(this.activeTab, true);
+    
+};
 
-    for(var i = 0, input; input = miniTab.inputArr[i]; i++) {
-      if(input.className.search("active") != -1) {
-       miniTab.activeTab = miniTab.currentTab = i;
-      }
-      /*input.style.borderBottom  = "0px";*/
-      /*input.style.paddingBottom = "6px";*/
-    }
-    miniTab.slideObj                = miniTab.ul.parentNode.appendChild(document.createElement("div"));
-    miniTab.slideObj.appendChild(document.createTextNode(String.fromCharCode(160)));
-    miniTab.slideObj.id             = "minitabs-sliding";
+minitabs.prototype.initSlide = function (pos, force) {
+  
+  if(!force && pos == this.activeTab) return;
+  this.setActive (this.activeTab,false);
+  this.activeTab = pos;
+  this.setActive (this.activeTab,true);
+  this.initAnim();
+};
+minitabs.prototype.setActive = function (pos,active) {
+  var input=this.li_s[pos].select('input.minitabs-submit')[0];
+  if (active)
+    input.addClassName('active');
+  else
+    input.removeClassName('active');
+};
+  
+minitabs.prototype.setSlidingTop = function () {
+  var delta=0;
+  /* up 5px for firefox */
+  /*window.console.log('agent=' + navigator.userAgent);*/
+  if (navigator.userAgent.match(/Firefox/)) delta=-5; 
+  this.slideObj.style.top  = (this.ul.offsetTop + this.li_s[this.activeTab].offsetTop 
+                             + this.input_s[this.activeTab].offsetTop + delta ) + "px";
+};
+  
+minitabs.prototype.initAnim = function() {
+  /* search for the input with type != hidden */
+  var input=this.li_s[this.activeTab].select('input.minitabs-submit')[0];
+  this.destX = parseInt(this.li_s[this.activeTab].offsetLeft + input.offsetLeft 
+                       + this.ul.offsetLeft);
+  this.destW = parseInt(input.offsetWidth);
+  this.t = 0;
+  this.b = this.slideObj.offsetLeft;
+  this.c = this.destX - this.b;
+  
+  this.bW = this.slideObj.offsetWidth;
+  this.cW = this.destW - this.bW;
+  
+  this.setSlidingTop();
+};
+  
+minitabs.prototype.slideIt = function() {
+  
+  // Has the browser text size changed?
+  var active_li = this.li_s[this.activeTab];
+  var active_input = this.input_s[this.activeTab];
+  if (this.aHeight != this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop) {
+    this.initAnim();
+    this.aHeight = this.ul.offsetTop + active_li.offsetTop + active_input.offsetTop;
+  }
+  
+  
+  if (this.t++ < this.d) {
+    var x = this.animate(this.t,this.b,this.c,this.d);
+    var w = this.animate(this.t,this.bW,this.cW,this.d);
+    
+    this.slideObj.style.left = parseInt(x) + "px";
+    this.slideObj.style.width = parseInt(w) + "px";
+  } else {
+    this.slideObj.style.left = this.destX + "px";
+    this.slideObj.style.width = this.destW +"px";
+  }
+};
+  
+minitabs.prototype.animate = function(t,b,c,d) {
+  if ((t/=d/2) < 1) return c/2*t*t + b;
+  return -c/2 * ((--t)*(t-2) - 1) + b;
+};
 
-    miniTab.setTop();
+minitabs.prototype.submit = function (message) {
+  /* save activeTab before confirmation; some browsers - firefox - send mouseout during confirm .. */
+  var submitTab = this.activeTab;
+  /* ask for confirmation if message is not empty */
+  if (message && ! confirm (message) ) return;
 
-    miniTab.slideObj.style.left     = (miniTab.ul.offsetLeft + miniTab.liArr[miniTab.activeTab].offsetLeft + 
-                                      miniTab.inputArr[miniTab.activeTab].offsetLeft) + "px";
-    miniTab.slideObj.style.width    = miniTab.inputArr[miniTab.activeTab].offsetWidth + "px";
-    miniTab.aHeight                 = (miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop + 
-                                      miniTab.inputArr[miniTab.activeTab].offsetTop);
-    miniTab.initSlide(miniTab.activeTab, true);
-    var intervalMethod = function() { miniTab.slideIt(); }
-    miniTab.animInterval = setInterval(intervalMethod,10);
+  /* get the form and trigger */
+  /*  window.console.log ("form=" + this.li_s[submitTab].up('form').submit(); */
+  this.li_s[submitTab].down('form').submit();
+  
+}
+  
+// globals
+var minitabs_namespace = {
+ init: function () {
+    window.console.log('init');
+    $$('div.minitabs').each (function (div) {   
+       /* create instance and attach it to the <div> element */
+       div.minitabs = new minitabs ();
+       div.minitabs.init(div);
+      } ) ;
+    
+    var intervalMethod = function () {
+      $$('div.minitabs').each (function (div) {
+         minitabs_namespace.the_minitabs(div).slideIt();
+       } ) ;
+    } ;
+    minitabs_namespace.animInterval = setInterval(intervalMethod,10);
   },
  
  cleanUp: function() {
-    clearInterval(miniTab.animInterval);
-    miniTab.animInterval = null;
-  },
- initSlide: function(pos, force) {
-    if(!force && pos == miniTab.activeTab) return;
-    miniTab.setActive (miniTab.activeTab,false);
-    miniTab.activeTab = pos;
-    miniTab.setActive (miniTab.activeTab,true);
-    miniTab.initAnim();
-  },
- setActive: function (pos,active) {
-    var input=getElementsByClassName(miniTab.liArr[pos],"minitabs-submit")[0];
-    var cn=input.className;
-    cn=cn.replace(" active","");
-    if (active) cn += " active";
-    input.className=cn;
-  },
- initAnim: function() {
-    /* search for the input with type != hidden */
-    var input=getElementsByClassName(miniTab.liArr[miniTab.activeTab],"minitabs-submit")[0];
-    miniTab.destX = parseInt(miniTab.liArr[miniTab.activeTab].offsetLeft + input.offsetLeft + miniTab.ul.offsetLeft);
-    miniTab.destW = parseInt(input.offsetWidth);
-    miniTab.t = 0;
-    miniTab.b = miniTab.slideObj.offsetLeft;
-    miniTab.c = miniTab.destX - miniTab.b;
-    miniTab.bW = miniTab.slideObj.offsetWidth;
-    miniTab.cW = miniTab.destW - miniTab.bW;
-    miniTab.setTop();
+    clearInterval(minitabs_namespace.animInterval);
+    minitabs_namespace.animInterval = null;
   },
  
- setTop: function () {
-    var delta=0;
-    /* up 5px for firefox */
-    if (navigator.userAgent.match(/Firefox/)) delta=-5; 
-    miniTab.slideObj.style.top  = (miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop 
-                                  + miniTab.inputArr[miniTab.activeTab].offsetTop + delta ) + "px";
-
+ resize: function (e) {
+    $$('div.minitabs').each ( function (div) { 
+       var mt = div.minitabs; 
+       mt.initSlide(mt.activeTab,true);
+      } );
   },
 
- slideIt:function() {
-    // Has the browser text size changed?
-    if(miniTab.aHeight != miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop + miniTab.inputArr[miniTab.activeTab].offsetTop) {
-      miniTab.initAnim();
-      miniTab.aHeight = miniTab.ul.offsetTop + miniTab.liArr[miniTab.activeTab].offsetTop + miniTab.inputArr[miniTab.activeTab].offsetTop
-    };
-    if(miniTab.t++ < miniTab.d) {
-      var x = miniTab.animate(miniTab.t,miniTab.b,miniTab.c,miniTab.d);
-      var w = miniTab.animate(miniTab.t,miniTab.bW,miniTab.cW,miniTab.d);
-      miniTab.slideObj.style.left = parseInt(x) + "px";
-      miniTab.slideObj.style.width = parseInt(w) + "px";
-    } else {
-      miniTab.slideObj.style.left = miniTab.destX + "px";
-      miniTab.slideObj.style.width = miniTab.destW +"px";
-    }
-  },
- animate: function(t,b,c,d) {
-    if ((t/=d/2) < 1) return c/2*t*t + b;
-    return -c/2 * ((--t)*(t-2) - 1) + b;
+ submit: function (id,message) {
+    $(id).minitabs.submit(message);
   },
 
- submit: function (message) {
-    /* save activeTab before confirmation; some browsers - firefox - send mouseout during confirm .. */
-    var submitTab = this.activeTab;
-    /* ask for confirmation if message is not empty */
-    if (message && ! confirm (message) ) return;
-    this.inputArr[submitTab].parentNode.parentNode.submit();
+ // find the enclosing minitabs object
+ the_minitabs: function (elem) {
+    if (elem.match('div.minitabs')) 
+      return elem.minitabs;
+    else 
+      return elem.up('div.minitabs').minitabs;
   }
-}
  
-window.onload = miniTab.init;
-window.onunload = miniTab.cleanUp;
+};
  
+window.onload   = minitabs_namespace.init;
+window.onunload = minitabs_namespace.cleanUp;
+window.onresize = minitabs_namespace.resize;