Trying to create a megamenu - hacing problems with loops

Trying to create a megamenu - hacing problems with loops

I am learning javascript (and jQuery). I cannot figure out how to make my megamenu work correctly. The script is taking all of the bins (list items underneath the top UL) and putting them underneath the very first menu item. To futher illustrate, when the page lodes my menu items look something like this:

  1.     <ul>
          <li>Top Level Menu Item 1</li>
          <li>Top Level Menu Item 2
            <ul>Bin A
              <li>Link 1</li>
              <li>Link 2</li>
            </ul>
          </li>
          <li>Top Level Menu Item 3
            <ul>Bin B
              <li>Link 1</li>
              <li>Link 2</li>
              <li>Link 3</li>
             </ul>
            <ul>Bin C
              <li>Link 1</li>
            </ul>
          </li>
        </ul>


















And so on, there are several top level menu items, each with a various number of bins underneath them. The number of top level menu items, bins and links underneath them are dynamic - I will not know how many there are at any given time.

What I am trying to do is take each top level menu item and apply a max height to the mega menu drop down (380). I need to ensure that the bins within the drop down are placed into columns that fit. My script is working as intended with one major exception - it is putting all of the bins in the first menu item (that has bins). So after my script runs it ends up looking like this:

  1.     <ul>
          <li>Top Level Menu Item 1</li>
          <li>Top Level Menu Item 2
            <ul>Bin A
              <li>Link 1</li>
              <li>Link 2</li>
            </ul>
            <ul>Bin B
              <li>Link 1</li>
              <li>Link 2</li>
              <li>Link 3</li>
             </ul>
            <ul>Bin C
              <li>Link 1</li>
            </ul>
          </li>
          <li>Top Level Menu Item 3</li>
        </ul>

















As you can see, Bin B and Bin C have been  moved into Top Level Menu Item 2 - which is not what I want. All of the bins need to stay under their respective parent. Everything else is working. In that the bins (now all within Top Menu Item 2) are placed in the correct columns and formatted correctly.

I must be using $(this) incorrectly or my loops are bad. I have spent the last few days looking at it and just cannot figure it out. The code is pasted below, I have tried to clean it up a bit and leave only relevant comments in - but it is a little messy.

I don't think the issue is with the activation or deactivation methods. It must be with the for loops, which I have probably done incorrectly. Again, everything is working as it should, except that all of the bins are placed in the first menu item that actually has bins (Top Level Menu Item 2).

  1.     //Create the top nav menu
        $('#main-menu ul.links').addClass("megamenu");

        $.fn.megamenu = function(options) {
          options = jQuery.extend({
          activate_action: "mouseover",
          deactivate_action: "mouseleave",
          show_method: "slideDown",
          hide_method: "slideUp",
          justify: "left",
          enable_js_shadow: false,
          shadow_size: 3,
          mm_timeout: 250
        }, options);

        var $megamenu_object = this;
        var binParent = $megamenu_object.children("li");         
             
        //calculate the height of each bin
        for ( var k=0 ; k < binParent.length ; k++ ) {
          var bin = binParent.eq(k).find("div.item-list");

        /**
        * Gets the dimensions of hidden elements, includes nested.
        * jQuery height(), width(), outerWidth() & outerHeight() do not play well with
        * hidden elements, so we need to create a function which injects css to give the
        * hidden elements a structure that the methods can grab onto.
        * @ctor
        * @tparam Boolean includeMargin Should we include margins in the calucation. Use this
        * for outerHeight type calculations.
        * @treturn Object dim Dimensions of the bin
        */
       
          $.fn.getHiddenDimensions = function(includeMargin) {
        var $item = this,
        props = { position: 'absolute', visibility: 'hidden', display: 'block' },
        dim = { width:0, height:0, innerWidth: 0, innerHeight: 0,outerWidth: 0,outerHeight: 0 },
        $hiddenParents = $item.parents().andSelf().not(':visible'),
        includeMargin = (includeMargin == null)? false : includeMargin;
               
        //add new css
        var oldProps = [];
        $hiddenParents.each(function() {
        var old = {};
            for ( var name in props ) {
              old[ name ] = this.style[ name ];
              this.style[ name ] = props[ name ];
            }

            oldProps.push(old);
          });

          //get dimensions of the bin
          dim.width = $item.width();
          dim.outerWidth = $item.outerWidth(includeMargin);
          dim.innerWidth = $item.innerWidth();
          dim.height = $item.height();
          dim.innerHeight = $item.innerHeight();
          dim.outerHeight = $item.outerHeight(includeMargin);

         //put css back to the way it was at the beginning of the function
         $hiddenParents.each(function(i) {
           var old = oldProps[i];
           for ( var name in props ) {
             this.style[ name ] = old[ name ];
           }
          });
          return dim;
        }
                 
        //set the max height of the menu drop down (bin parent)
        var maxHeight = 380;
                   
        //If the bin parent (the main menu item) has children (bins), then
        //group bins into divs with a class of column, stacked or full-column.
        //base groupings on max height of bin parent
      
        if (bin.length > 0) {
          for ( var i=0 ; i < bin.length ; i++ ) {
            var binIndex = i;
        var binDims = bin.eq(i).getHiddenDimensions();
        var binHeight = binDims['outerHeight'];
        var binWidth = binDims['outerWidth'];
                         
        //assign columns to individual bins that are within 20px of the max height
        if (binHeight > maxHeight) {
          bin.eq(i).addClass('full-column');
        } else {                     
          //stack remaining bins in columns
          var colHeight = 0;
          bin.eq(i).addClass('stacked');
        }
          }
         } 
        }

        $('.stacked').wrapAll('<div id="tostack" class="item-list item-0"></div>');
        //caluclate height of tostack div and divide by maxHeight in order to determine 
        //no of columns
        var stackDims = $('#tostack').getHiddenDimensions();
        var noCols = Math.ceil(stackDims['outerHeight']/maxHeight);
        //var source = $("#tostack").contents();
        var totLength = $('.stacked').length;
        var divCol = Math.ceil(totLength/noCols);
        var fullExists = $('div').hasClass('full-column');
       
        if (fullExists == true && noCols > 3) {
          noCols = 3;
        } else if (noCols > 4) {
          noCols = 4;
        }
       
        for (c = 1; c < noCols; c++) {
          //replicate the original column, replace id with something unique add class
          $('#tostack').clone(true)
          .attr('id','item-'+c).attr('class','item-list item item-'+c)
          .insertAfter('#tostack');
        }
             
        //wrap divs across columns
        var printDivs = divCol * 1;
        $('.item-0').children().slice(printDivs, totLength).detach();
       
        for (c=1; c <= (noCols - 1); c++) {
          var printDivs = divCol * c;
          $('.item-'+c).find('div.stacked').slice(0, printDivs).hide().remove();
          $('.item-'+c).find('div.stacked').slice(printDivs, totLength).hide().remove();
        }
             
        if( options.activate_action == "click" ) options.mm_timeout = 0;
          $megamenu_object.children("li").each(function(){
          jQuery(this).addClass("mm-item");
          jQuery(".mm-item").css({ 'float': options.justify });
          jQuery(this).find("div.view-megamenumain").addClass("mm-item-content");
          jQuery(this).find("a:first").addClass("mm-item-link");
          var $mm_item_content = jQuery(this).find(".mm-item-content");
          var $mm_item_link = jQuery(this).find(".mm-item-link");
          $mm_item_content.hide();
               
          jQuery(document).bind("click", function(){
          jQuery(".mm-item-content").hide();
          jQuery(".mm-item-link").removeClass("mm-item-link-hover");
        });

        jQuery(this).bind("click", function(e){
         e.stopPropagation();
        });
       
        $mm_item_content.wrapInner('<div class="mm-content-base"></div>');

        if(options.enable_js_shadow == true) {
          $mm_item_content.append('<div class="mm-js-shadow"></div>');
        }

        var $mm_timer = 0;
               
        // Activation Method Starts
        jQuery(this).bind(options.activate_action, function(e){
          e.stopPropagation();
          var mm_item_link_obj = jQuery(this).find("a.mm-item-link");
          var mm_item_content_obj = jQuery(this).find("div.mm-item-content");
          clearTimeout($mm_timer);
          $mm_timer = setTimeout(function(){ //Emulate HoverIntent
          mm_item_link_obj.addClass("mm-item-link-hover");
          mm_item_content_obj.css({
          'top': ($mm_item_link.position().top + $mm_item_link.outerHeight()) - 1 +"px",
          'left': ($mm_item_link.offset().left) - 5 + 'px'
        })
                   
        if(options.justify == "left"){
          mm_item_content_obj.css({ 'width': '100%' });
          var mm_object_right_end = $megamenu_object.position().left + $megamenu_object.outerWidth();

         // Coordinates of the right end of the megamenu object
         var mm_content_right_end = $mm_item_link.position().left + $mm_item_content.outerWidth();

        // Coordinates of the right end of the megamenu content
        if( mm_content_right_end >= mm_object_right_end ) { 7
          // Menu content exceeding the outer box
          mm_item_content_obj.css({
          'left': ($mm_item_link.position().left - (mm_content_right_end - mm_object_right_end)) - 8 + 'px'
         }); // Limit megamenu inside the outer box
         }
         } else if( options.justify == "right" ) {
        var mm_object_left_end = $megamenu_object.offset().left;
        // Coordinates of the left end of the megamenu object
        var mm_content_left_end = $mm_item_link.offset().left - mm_item_content_obj.outerWidth() +
        $mm_item_link.outerWidth() + 5;
        // Coordinates of the left end of the megamenu content
        if( mm_content_left_end <= mm_object_left_end ) {
              // Menu content exceeding the outer box
         mm_item_content_obj.css({
          'left': mm_object_left_end + 2 + 'px'
        }); // Limit megamenu inside the outer box
        } else {
          mm_item_content_obj.css({
           'left': mm_content_left_end + 'px'
            }); // Limit megamenu inside the outer box
           }
          }
                   
          switch(options.show_method) {
        case "simple":
          mm_item_content_obj.show();
        break;
        case "slideDown":
          mm_item_content_obj.height("auto");
          mm_item_content_obj.slideDown('400');
        break;
        case "fadeIn":
          mm_item_content_obj.fadeTo('fast', 1);
        break;
        default:
          mm_item_content_obj.each( options.show_method );
        break;
           }
          }, options.mm_timeout);
        });

        // Activation Method Ends
               
                // Deactivation Method Starts
                jQuery(this).bind(options.deactivate_action, function(e){
                  e.stopPropagation();
                  clearTimeout($mm_timer);
                  var mm_item_link_obj = jQuery(this).find("a.mm-item-link");
                  var mm_item_content_obj = jQuery(this).find("div.mm-item-content");
        //mm_item_content_obj.stop();
                  switch(options.hide_method) {
                    case "simple":
                          mm_item_content_obj.hide();
                          mm_item_link_obj.removeClass("mm-item-link-hover");
                          break;
                    case "slideUp":
                          mm_item_content_obj.slideUp( '400',  function() {
                            mm_item_link_obj.removeClass("mm-item-link-hover");
                          });
                          break;
                    case "fadeOut":
                          mm_item_content_obj.fadeOut( 'fast', function() {
                            mm_item_link_obj.removeClass("mm-item-link-hover");
                          });
                          break;
                    default:
                          mm_item_content_obj.each( options.hide_method );
                          mm_item_link_obj.removeClass("mm-item-link-hover");
                          break;
                  }
                  if(mm_item_content_obj.length < 1) mm_item_link_obj.removeClass("mm-item-link-hover");
                });
        //Deactivation Method Ends
               
              });
              this.find(">li:last").after('<li class="clear-fix"></li>');
              this.show();
            };

            $("#main-menu ul.links").megamenu();

































































































































































































































































Any help is greatly appreciated.