Adding a MORE button

based on Distributions Open wireframe

by mlhDevelopment

HTML

<b>The more button dynamically grabbing extra items:</b>

<div class="width-constraint">
    The red box is where the menu would be
    <ul class="datalist">
        <li>Alpha</li>
        <li>Beta</li>
        <li>Gamma Delta</li>
        <li>Echo</li>
        <li>Foxtrot</li>
        <li>Golf</li>
        <li>Hotel</li>
        <li>India</li>
    </ul>
    this is just extra text; the orange box is the site container, where content can go above and
    below the button bar
</div>

<br />
<hr />
<b>The more button statically placed; or, effectively after jQuery manipulates the DOM:</b>


<ul>
    <li>Alpha</li>
    <li>Beta</li>
    <li>Gamma Delta</li>
    <li>Echo</li>
    <li class="morebutton">
        <a href='#'>More</a>
        <ul>
            <li>Foxtrot</li>
            <li>Golf</li>
            <li>Hotel</li>
            <li>India</li>
        </ul>
    </li>
</ul>

    
<br style="clear: both;" />
<br />
<hr />
<b>This is a test when the more button is not needed:</b>
    
<div class="width-constraint">
    <ul class="datalist">
        <li>Alpha</li>
        <li>Beta</li>
        <li>Gamma Delta</li>
        <li>Echo</li>
    </ul>
</div>

CSS

* { margin: 0; padding: 0; }
.width-constraint { 
    width: 302px; 
    border: dashed 1px orange; 
}

.datalist {
    border: dashed 1px red;
    height: 52px;
    overflow: hidden;
}

ul li {
    display: block;
    float: left;
    margin: 5px;
    padding: 5px;
    border: 1px solid #aaa;
    height: 30px;
}

ul li.morebutton {
    padding: 0;
    height: 40px;
}
ul li.morebutton > a { 
    display: block;
    height: 30px;
    padding: 5px;
}
.morebutton ul { position: absolute; display: none; }
.morebutton.open ul { display: block; }
.morebutton ul li {
    float: none;
    background-color: white;
    margin: 0 0 -1px -1px;
}

JavaScript

// The more button click handler
var fnMoreButtonClick = function(evt) {
    evt.preventDefault();
    $(this).parent().toggleClass("open");
};

// This is used if the more button is placed statically 
$('.morebutton > a').click(fnMoreButtonClick);

// For dynamically grabbing extra (clipped) items)
$(".datalist").each(function() {
    var $this = $(this);
    
    // Figure out the last item being displayed
    var parentHeight = $this.height();
    var lastVisibleItem = $this.children("li")
        .filter(function() { return $(this).position().top < parentHeight; })
        .last();
    debugger;
    
    // Only add the more button if there are hidden items
    if(lastVisibleItem.next().length) {
    
        // Add the more button to the list
        var liMore = $("<li class='morebutton'><a href='#'>More</a></li>")
            .find('a').click(fnMoreButtonClick).end()
            .insertAfter(lastVisibleItem);
        
        // Graduate the more button until it is displayed
        while(liMore.position().top >= parentHeight) {
            var prevLi = liMore.prev();
            liMore.detach().insertBefore(prevLi);
        }
        
        // Take all the subsequent items and put them "inside" the more button
        liMore.nextAll().detach().appendTo($("<ul />").appendTo(liMore));
    }
});