Index: rotor.js
===================================================================
--- rotor.js	(revision 328)
+++ rotor.js	(working copy)
@@ -1,6 +1,8 @@
 // $Id: rotor.js,v 1.1.2.2 2008/04/29 22:53:59 nestormata Exp $ 
-var rotor_items = new Array();
-var actual_item = 0;
+
+// include jquery cycle core minified (http://malsup.com/jquery/cycle/download.html)
+(function(G){var A="2.24";var B=G.browser.msie&&/MSIE 6.0/.test(navigator.userAgent);function D(){if(window.console&&window.console.log){window.console.log("[cycle] "+Array.prototype.join.call(arguments,""))}}G.fn.cycle=function(I){return this.each(function(){if(I===undefined||I===null){I={}}if(I.constructor==String){switch(I){case"stop":if(this.cycleTimeout){clearTimeout(this.cycleTimeout)}this.cycleTimeout=0;G(this).data("cycle.opts","");return ;case"pause":this.cyclePause=1;return ;case"resume":this.cyclePause=0;return ;default:I={fx:I}}}else{if(I.constructor==Number){var N=I;I=G(this).data("cycle.opts");if(!I){D("options not found, can not advance slide");return }if(N<0||N>=I.elements.length){D("invalid slide index: "+N);return }I.nextSlide=N;if(this.cycleTimeout){clearTimeout(this.cycleTimeout);this.cycleTimeout=0}E(I.elements,I,1,1);return }}if(this.cycleTimeout){clearTimeout(this.cycleTimeout)}this.cycleTimeout=0;this.cyclePause=0;var Q=G(this);var O=I.slideExpr?G(I.slideExpr,this):Q.children();var K=O.get();if(K.length<2){D("terminating; too few slides: "+K.length);return }var J=G.extend({},G.fn.cycle.defaults,I||{},G.metadata?Q.metadata():G.meta?Q.data():{});if(J.autostop){J.countdown=J.autostopCount||K.length}Q.data("cycle.opts",J);J.container=this;J.elements=K;J.before=J.before?[J.before]:[];J.after=J.after?[J.after]:[];J.after.unshift(function(){J.busy=0});if(J.continuous){J.after.push(function(){E(K,J,0,!J.rev)})}if(B&&J.cleartype&&!J.cleartypeNoBg){C(O)}var S=this.className;J.width=parseInt((S.match(/w:(\d+)/)||[])[1])||J.width;J.height=parseInt((S.match(/h:(\d+)/)||[])[1])||J.height;J.timeout=parseInt((S.match(/t:(\d+)/)||[])[1])||J.timeout;if(Q.css("position")=="static"){Q.css("position","relative")}if(J.width){Q.width(J.width)}if(J.height&&J.height!="auto"){Q.height(J.height)}if(J.random){J.randomMap=[];for(var L=0;L<K.length;L++){J.randomMap.push(L)}J.randomMap.sort(function(U,T){return Math.random()-0.5});J.randomIndex=0;J.startingSlide=J.randomMap[0]}else{if(J.startingSlide>=K.length){J.startingSlide=0}}var M=J.startingSlide||0;O.css({position:"absolute",top:0,left:0}).hide().each(function(T){var U=M?T>=M?K.length-(T-M):M-T:K.length-T;G(this).css("z-index",U)});G(K[M]).css("opacity",1).show();if(G.browser.msie){K[M].style.removeAttribute("filter")}if(J.fit&&J.width){O.width(J.width)}if(J.fit&&J.height&&J.height!="auto"){O.height(J.height)}if(J.pause){Q.hover(function(){this.cyclePause=1},function(){this.cyclePause=0})}var R=G.fn.cycle.transitions[J.fx];if(G.isFunction(R)){R(Q,O,J)}else{if(J.fx!="custom"){D("unknown transition: "+J.fx)}}O.each(function(){var T=G(this);this.cycleH=(J.fit&&J.height)?J.height:T.height();this.cycleW=(J.fit&&J.width)?J.width:T.width()});J.cssBefore=J.cssBefore||{};J.animIn=J.animIn||{};J.animOut=J.animOut||{};O.not(":eq("+M+")").css(J.cssBefore);if(J.cssFirst){G(O[M]).css(J.cssFirst)}if(J.timeout){if(J.speed.constructor==String){J.speed={slow:600,fast:200}[J.speed]||400}if(!J.sync){J.speed=J.speed/2}while((J.timeout-J.speed)<250){J.timeout+=J.speed}}if(J.easing){J.easeIn=J.easeOut=J.easing}if(!J.speedIn){J.speedIn=J.speed}if(!J.speedOut){J.speedOut=J.speed}J.slideCount=K.length;J.currSlide=M;if(J.random){J.nextSlide=J.currSlide;if(++J.randomIndex==K.length){J.randomIndex=0}J.nextSlide=J.randomMap[J.randomIndex]}else{J.nextSlide=J.startingSlide>=(K.length-1)?0:J.startingSlide+1}var P=O[M];if(J.before.length){J.before[0].apply(P,[P,P,J,true])}if(J.after.length>1){J.after[1].apply(P,[P,P,J,true])}if(J.click&&!J.next){J.next=J.click}if(J.next){G(J.next).bind("click",function(){return F(K,J,J.rev?-1:1)})}if(J.prev){G(J.prev).bind("click",function(){return F(K,J,J.rev?1:-1)})}if(J.pager){H(K,J)}J.addSlide=function(U){var T=G(U),V=T[0];if(!J.autostopCount){J.countdown++}K.push(V);if(J.els){J.els.push(V)}J.slideCount=K.length;T.css("position","absolute").appendTo(Q);if(B&&J.cleartype&&!J.cleartypeNoBg){C(T)}if(J.fit&&J.width){T.width(J.width)}if(J.fit&&J.height&&J.height!="auto"){O.height(J.height)}V.cycleH=(J.fit&&J.height)?J.height:T.height();V.cycleW=(J.fit&&J.width)?J.width:T.width();T.css(J.cssBefore);if(J.pager){G.fn.cycle.createPagerAnchor(K.length-1,V,G(J.pager),K,J)}if(typeof J.onAddSlide=="function"){J.onAddSlide(T)}};if(J.timeout||J.continuous){this.cycleTimeout=setTimeout(function(){E(K,J,0,!J.rev)},J.continuous?10:J.timeout+(J.delay||0))}})};function E(N,I,M,O){if(I.busy){return }var L=I.container,Q=N[I.currSlide],P=N[I.nextSlide];if(L.cycleTimeout===0&&!M){return }if(!M&&!L.cyclePause&&((I.autostop&&(--I.countdown<=0))||(I.nowrap&&!I.random&&I.nextSlide<I.currSlide))){if(I.end){I.end(I)}return }if(M||!L.cyclePause){if(I.before.length){G.each(I.before,function(R,S){S.apply(P,[Q,P,I,O])})}var J=function(){if(G.browser.msie&&I.cleartype){this.style.removeAttribute("filter")}G.each(I.after,function(R,S){S.apply(P,[Q,P,I,O])})};if(I.nextSlide!=I.currSlide){I.busy=1;if(I.fxFn){I.fxFn(Q,P,I,J,O)}else{if(G.isFunction(G.fn.cycle[I.fx])){G.fn.cycle[I.fx](Q,P,I,J)}else{G.fn.cycle.custom(Q,P,I,J)}}}if(I.random){I.currSlide=I.nextSlide;if(++I.randomIndex==N.length){I.randomIndex=0}I.nextSlide=I.randomMap[I.randomIndex]}else{var K=(I.nextSlide+1)==N.length;I.nextSlide=K?0:I.nextSlide+1;I.currSlide=K?N.length-1:I.nextSlide-1}if(I.pager){G.fn.cycle.updateActivePagerLink(I.pager,I.currSlide)}}if(I.timeout&&!I.continuous){L.cycleTimeout=setTimeout(function(){E(N,I,0,!I.rev)},I.timeout)}else{if(I.continuous&&L.cyclePause){L.cycleTimeout=setTimeout(function(){E(N,I,0,!I.rev)},10)}}}G.fn.cycle.updateActivePagerLink=function(I,J){G(I).find("a").removeClass("activeSlide").filter("a:eq("+J+")").addClass("activeSlide")};function F(I,J,M){var L=J.container,K=L.cycleTimeout;if(K){clearTimeout(K);L.cycleTimeout=0}if(J.random&&M<0){J.randomIndex--;if(--J.randomIndex==-2){J.randomIndex=I.length-2}else{if(J.randomIndex==-1){J.randomIndex=I.length-1}}J.nextSlide=J.randomMap[J.randomIndex]}else{if(J.random){if(++J.randomIndex==I.length){J.randomIndex=0}J.nextSlide=J.randomMap[J.randomIndex]}else{J.nextSlide=J.currSlide+M;if(J.nextSlide<0){if(J.nowrap){return false}J.nextSlide=I.length-1}else{if(J.nextSlide>=I.length){if(J.nowrap){return false}J.nextSlide=0}}}}D("nextSlide: "+J.nextSlide+"; randomIndex: "+J.randomIndex);if(J.prevNextClick&&typeof J.prevNextClick=="function"){J.prevNextClick(M>0,J.nextSlide,I[J.nextSlide])}E(I,J,1,M>=0);return false}function H(J,K){var I=G(K.pager);G.each(J,function(L,M){G.fn.cycle.createPagerAnchor(L,M,I,J,K)});G.fn.cycle.updateActivePagerLink(K.pager,K.startingSlide)}G.fn.cycle.createPagerAnchor=function(K,L,I,J,M){var N=(typeof M.pagerAnchorBuilder=="function")?G(M.pagerAnchorBuilder(K,L)):G('<a href="#">'+(K+1)+"</a>");if(N.parents("body").length==0){N.appendTo(I)}N.bind(M.pagerEvent,function(){M.nextSlide=K;var P=M.container,O=P.cycleTimeout;if(O){clearTimeout(O);P.cycleTimeout=0}if(typeof M.pagerClick=="function"){M.pagerClick(M.nextSlide,J[M.nextSlide])}E(J,M,1,M.currSlide<K);return false})};function C(K){function J(L){var L=parseInt(L).toString(16);return L.length<2?"0"+L:L}function I(N){for(;N&&N.nodeName.toLowerCase()!="html";N=N.parentNode){var L=G.css(N,"background-color");if(L.indexOf("rgb")>=0){var M=L.match(/\d+/g);return"#"+J(M[0])+J(M[1])+J(M[2])}if(L&&L!="transparent"){return L}}return"#ffffff"}K.each(function(){G(this).css("background-color",I(this))})}G.fn.cycle.custom=function(O,L,M,I){var N=G(O),K=G(L);K.css(M.cssBefore);var J=function(){K.animate(M.animIn,M.speedIn,M.easeIn,I)};N.animate(M.animOut,M.speedOut,M.easeOut,function(){if(M.cssAfter){N.css(M.cssAfter)}if(!M.sync){J()}});if(M.sync){J()}};G.fn.cycle.transitions={fade:function(J,K,I){K.not(":eq("+I.startingSlide+")").css("opacity",0);I.before.push(function(){G(this).show()});I.animIn={opacity:1};I.animOut={opacity:0};I.cssBefore={opacity:0};I.cssAfter={display:"none"}}};G.fn.cycle.ver=function(){return A};G.fn.cycle.defaults={fx:"fade",timeout:4000,continuous:0,speed:1000,speedIn:null,speedOut:null,next:null,prev:null,prevNextClick:null,pager:null,pagerClick:null,pagerEvent:"click",pagerAnchorBuilder:null,before:null,after:null,end:null,easing:null,easeIn:null,easeOut:null,shuffle:null,animIn:null,animOut:null,cssBefore:null,cssAfter:null,fxFn:null,height:"auto",startingSlide:0,sync:1,random:0,fit:0,pause:0,autostop:0,autostopCount:0,delay:0,slideExpr:null,cleartype:0,nowrap:0}})(jQuery)
+
 var rotor_interval = null;
 var rotor_init = false;
 $(window).load(
@@ -20,39 +22,33 @@
     }
     rotor_init = true;
     
+	// set speed to an appropriate value
+	rotor_speed == 0? rotor_speed = 1 : rotor_speed = rotor_speed * 1000;
+
     // Checks that the rotor enabled variable has being set to true
     // this must be done also by setting the rotor_time variable and the
     // rotor div. This is done by the drupal module.
     if(typeof rotor_enabled != 'undefined' && rotor_enabled) {
-        //debugger;
-      $('.rotor_content > .rotor_tab').click(function() {
-        //clearInterval(rotor_interval);
-        //rotor_interval = null;
-        animate_rotor_item($(this).parent());
-      });
-      animate_rotor_item();
-      wait_next_rotor();
+      animate_rotor_items();
     }   
-}
+};
 
-function animate_rotor_item(rotor_item) {
-  if(typeof rotor_item == "undefined" || typeof rotor_item == "number"){
-    rotor_item = $('.rotor_content').get(actual_item);
-  }
-  $('#rotor > .rotor_content > .rotor_content_detail').hide();
-  $('#rotor > .rotor_content > .rotor_tab').removeClass('selected');
-  $('.rotor_content_detail', rotor_item).show();
-  $('.rotor_tab', rotor_item).addClass('selected');
-  var contents = $('.rotor_content');
-  var actual = contents.get(actual_item);
-  actual_item = (actual_item + 1) % contents.length;
-}
-
-function wait_next_rotor() {
-  var contents = $('.rotor_content');
-  if(contents.length > 0) {
-    if (!rotor_interval) {
-        rotor_interval = setInterval(animate_rotor_item, rotor_time * 1000);
-    }
-  }
-}
+function animate_rotor_items(){
+	// redefine Cycle's updateActivePagerLink function 
+	$.fn.cycle.updateActivePagerLink = function(pager, currSlideIndex){
+		$(pager).find('.rotor_tab').removeClass('selected')
+		.filter('.rotor_tab:eq(' + currSlideIndex + ')').addClass('selected');
+	};
+	
+	$('#rotor_items').cycle({
+		// I specified a 1px height to stop the divs being shifetd down when tabs are not grouped
+		// This only happens in Firefox (is it because they are absolutely positioned by cycle?)
+		height: '1px',
+		timeout: rotor_time * 1000,
+		speed: rotor_speed,
+		pager: '#rotor_tabs',
+		pagerAnchorBuilder: function(idx, slide){
+			return '#rotor_tabs';
+		}
+	});
+};
Index: rotor.module
===================================================================
--- rotor.module	(revision 328)
+++ rotor.module	(working copy)
@@ -120,6 +120,14 @@
     '#size' => 2,
     '#description' => t('The time in seconds that will be shown every rotor item before change to the next one.'),
   );
+  $form['speed'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Speed'),
+    '#default_value' => variable_get('rotor_speed', 1),
+    '#rows' => 1,
+    '#size' => 2,
+    '#description' => t('The time in seconds of the transition effect between each rotor item. (set to 0 for no transition)'),
+  );
   $form['show_tab'] = array(
     '#type' => 'checkbox',
     '#title' => t('Enable tabs'),
@@ -163,6 +171,7 @@
   if ($values['op'] == $values['submit']) {
     variable_set('rotor_max_items', $values['max_items']);
     variable_set('rotor_seconds', $values['time']);
+    variable_set('rotor_speed', $values['speed']);
     variable_set('rotor_show_tabs', $values['show_tab']);
     variable_set('rotor_group_tabs', $values['group_tabs']);
     variable_set('rotor_imagecache_preset', $values['imagecache']);
@@ -372,9 +381,11 @@
 
   // Prints the script variables and includes the rotor javascript file.
   $time = variable_get('rotor_seconds', 10);
+  $speed = variable_get('rotor_speed', 1);
   drupal_add_js(drupal_get_path('module', 'rotor') . '/rotor.js');
   drupal_add_js('var rotor_enabled = true;', 'inline');
   drupal_add_js('var rotor_time = ' . $time . ';', 'inline');
+  drupal_add_js('var rotor_speed = ' . $speed . ';', 'inline');
 
   // Print the rotor items.
   $output = '<div id="rotor">';
@@ -399,7 +410,7 @@
   $group_tabs = variable_get('rotor_group_tabs', ROTOR_GROUP_TABS);
   $output = '';
   if($show_tabs && $group_tabs == ROTOR_GROUP_TABS) {
-    $output = '<div class="rotor_tabs">';
+    $output = '<div id="rotor_tabs">';
     foreach ($items as $item) {
       $output .= '<div class="rotor_tab">' . $item->title . '</div>';
     }
@@ -414,10 +425,11 @@
  * @param array $items The array of items.
  */
 function theme_rotor_items($items = array()) {
-  $output = '';
+  $output = '<div id="rotor_items">';
   foreach ($items as $item) {
       $output .= theme('rotor_item', $item);
   }
+  $output .= '</div>';
   return $output;
 }
 
@@ -433,7 +445,7 @@
   if($show_tabs && $group_tabs == ROTOR_DONT_GROUP_TABS) {
     $output .= '<div class="rotor_tab">' . $item->title . '</div>';
   }
-  $output .= '<div class="rotor_content_detail" style="display:none">'
+  $output .= '<div class="rotor_content_detail">'
     . ($item->rotor_image
     ? theme('rotor_image', $item->rotor_image)
     : check_markup($item->body)) 
Index: rotor.install
===================================================================
--- rotor.install	(revision 328)
+++ rotor.install	(working copy)
@@ -16,6 +16,7 @@
   drupal_uninstall_schema('rotor');
   variable_del('rotor_max_items');
   variable_del('rotor_seconds');
+  variable_del('rotor_speed');
   variable_del('rotor_show_tabs');
   variable_del('rotor_group_tabs');
   drupal_set_message(t('Rotor unistalled'));
