jQuery Slide Menu… Another Cause I Can Experiment

So for no real reason at all I had it in my mind that I wanted to make a horizontal menu with jQuery that would work like that weird scrolling menu thing that Macs have. No idea what it’s called. So basically I don’t need it, have no reason for it, but damnit I’m going to make it happen and I did it with only 3 things from jquery.com; 1.3.2, ui 1.7.2, and jquery.timer . Now this is still rough in the sense it has no real styling but it works tried and true functionality wise.

The main idea is that there are two scroll arrows, one on each side, and X amount of divs. Now at the start, a certain amount of divs are hidden (global variable). When hovering over the left pager, for example, it causes one on the right to hide while one on the left appears giving the feeling of the items sliding.

EXAMPLE HERE!!11

The markup is simple, a holder with x number of elements that are “menuitems” and two pager divs.

<div class="mainHolder">
  <div class="leftPager green floatLeft"><</div>
  <div class="menuItem floatLeft blue">1</div>
  <div class="menuItem floatLeft red">2</div>
  <div class="menuItem floatLeft yellow">3</div>
  <div class="menuItem floatLeft blue">4</div>
  <div class="menuItem floatLeft red">5</div>
  <div class="menuItem floatLeft yellow">6</div>
  <div class="menuItem floatLeft blue">7</div>
  <div class="rightPager green floatLeft">></div>
</div>

I think from the classes you can tell what you need to know about them.

First thing we need from jQuery is methods to find various elements in the container when paging.

//When using the left pager, it's important to find the first visible element
//then find the item before it so that it can be shown.
function getNextInLineBack(menuItems)
{
  var oneBefore = null;

  for (var loopCounter = 0; loopCounter < menuItems.length; loopCounter++)
  {
    if(jQuery(menuItems[loopCounter]).is(":visible") && loopCounter > 0)
    {
      oneBefore = jQuery(menuItems[loopCounter - 1 ]);
      break;
    }
  }

  return oneBefore;
}

//Find the first visible element from the beginning.
//This will be needed when paging right since it will have to be hidden
function getFirstVisible(menuItems)
{
  var firstVisible = null;

  for (var loopCounter = 0; loopCounter < menuItems.length; loopCounter++)
  {
    if(jQuery(menuItems[loopCounter]).is(":visible") && loopCounter < menuItems.length - maximumToShow)
    {
        firstVisible = menuItems[loopCounter];
        break;
    }
  }
  return firstVisible;
} 

//Get the last possible visible item
//If the item is in an index less than the maximum number to show, then null is returned since there has to be no more or less than the maximumToShow.
function getLastVisible(menuItems)
{
  var lastVisible = null;
  for (var loopCounter = menuItems.length - 1; loopCounter > maximumToShow - 1; loopCounter--)
  {
    if(jQuery(menuItems[loopCounter]).is(":visible"))
    {
      lastVisible = menuItems[loopCounter];
      break;
    }
  }

  return lastVisible;
}

//Find the first visible from the end
//Pretty simple, this will be important when paging left since this
//will be the next item to be hidden
function getNextInLineFront(menuItems)
{
  var lastOne = null;

  for (var loopCounter = menuItems.length-1; loopCounter > -1; loopCounter--)
  {
    if(jQuery(menuItems[loopCounter]).is(":visible"))
    {
      lastOne = menuItems[loopCounter + 1];
      break;
    }
  }

  return lastOne;
}

Next is a method that is just used to stop having to repeat the same thing over and over when needing a list of all the menu items.

function getMenuItems(mainHolder)
{
  return jQuery(mainHolder).children(".menuItem");
}

Next is the method to handle what item to show and what item to hide when the pager has the mouse over it. Instead of having methods for the right and left pager, I just ended up having the methods for finding the item to hide and show sent through as parameters.

function showHideOnHover(pager, timer, getHideMethod, getShowMethod)
{
  //This is just candy for changing the color of the pager when the mouse
  //is over it
  jQuery(pager).removeClass("green");
  jQuery(pager).addClass("orange");

  //Remember those methods I passed through, well here they
  //are in use.  I'm using them to get the item to hide and the item
  //to show along with the list of items.
  var menuItems = getMenuItems(jQuery(pager).parent());
  var hide = getHideMethod(menuItems);
  var show = getShowMethod(menuItems);

  //If neither is null, then go ahead and show/hide
  //If either one is null, something isn't right and the timer
  //needs to be stopped.... timer??  Well I'll get to that
  //next.
  if(show != null && hide != null)
  {
    jQuery(hide).hide( "slide", { direction: "right" } , 0);
    jQuery(show).show( "slide", { direction: "left" } , 100);
  }
  else
  {
    timer.stop();
  }
}

Now for the method above the last one, this one involves the timer passed in the last method. This method actually sets the mouseover/mouseout events (aka hover). When mouseover, the timer is created and the showHideOnHover method is called every 500 units, that’s we’ll call tools, (Not sure how much that is, seems like a half second) after the first time it’s called. On mouseout, the timer is stopped, nulled out, and the pager changes it’s color.

function setPager(pager, hideMethod, showMethod)
{
  //Making the timer variable "global" to the events so that I know
  //I have the same timer for both mouseover and mouseout.
  var newTimer;
  pager.hover
  (
    //Mouseover method
    function()
    {
      var first = true;
      //This sets the timer, consequently starting the method for the first time.
      //Why timer doesn't have a start method I don't know.  Ask jquery.com.
      //The first thing is just so that the first time around it runs right away,
      //then each call afterwards comes every 500 tools.
      newTimer = jQuery.timer
                      (
                         0, //First time through, runs after 0 tools.
                         function(timer)
                         {
                           showHideOnHover(pager, timer, hideMethod, showMethod);
                           //If this is the first time through, reset
                           //timer to run every 500 tools.
                           if(first)
                           {
                              timer.reset(500);
                              first = false;
                           }
                         }
                       );
    },

    //Mouseout method
    function()
    {
      //mouse is done, stop the timer
      newTimer.stop();
      newTimer = null;
      jQuery(pager).addClass("green");
      jQuery(pager).removeClass("orange")
    }
  );
}

Now for the method above the one… above. This is used to set the children of the passed in holder.

function setChildrenDivs(mainHolder)
{
  //Get the items for the holder
  var menuItems = getMenuItems(mainHolder);

  //Hide all the items after the first X items (maximumToShow)
  for (var loopCounter = 0; loopCounter < menuItems.length; loopCounter++)
  {
    if(loopCounter > maximumToShow - 1)
    {
      jQuery(menuItems[loopCounter]).hide();
    }
  }

  //set the pagers.
  setPager(jQuery(mainHolder).children(".leftPager"), getLastVisible, getNextInLineBack);
  setPager(jQuery(mainHolder).children(".rightPager"),getFirstVisible, getNextInLineFront);
}

FINALLY THE END! This is the document.ready method used to set this whole joke in motion. maximumToShow is just how many items to show at a time and is global.

var maximumToShow = 5;

jQuery(document).ready
(
  function()
  {
    //Find every holder on the page and set everything in motion.
    var mainHolders = jQuery(".mainHolder");
    for (var loopCounter = 0; loopCounter < mainHolders.length; loopCounter++)
    {
      setChildrenDivs(mainHolders[loopCounter]);
    }
  }
);

Why the timer? If you haven’t figured that out yet, well it’s because I had issues with how to get the menu to keep doing it’s thing as long as the user had his/her mouse over a pager. I didn’t want this to be a click menu because, let’s be honest, that would be much easier. So as is, the timer is started the moment the mouse is over a pager and hides/shows an item. Then every 500 tools the mouse is over the pager, it continues the hide/show until it runs out of items to show/hide. (End of the list)

Uhg that’s annoying to type out even with cut and paste so I will host it here.

I suppose the next part of this would have the items blow up or something when hovering over them but that should be much easier than this was.