So I needed a method to take a long, nested list and turning it into a compact, multiple acolumn list, for example, in order to display it as sort of a site map.
Being a huge fan of jQuery, it was naturally my go-to library of choice.
Scanning the plugins site, I can’t find a fair solution.
One of the caveats of many methodologies is that each list item has to be the same height. This works Ok for a lot of use cases, but what if your the source for the list contain arbitrary text you don’t control.
So, I started from scratch. Instead of relying on consistent line heights, and applying different margin settings to list elements, I decided to decompose the large source list into several smaller lists (one for each column) and then use a css float
parameter to make them all appear side-by-side.
Features
- Styling of ordered/unordered lists
- Configurable column-count and width
- Easy restoring to “non-column” layout
- Requirements: JQuery 1.2 (download)
- Browser-Compatibility: Firefox 1.5+, IE6+, Safari 2, Opera 9+
Usage
Just apply to any group of DOM-elements gathered by the amazing JQuery-selectors. The provided arguments are optional (these are the default values).
$('ol').makeacolumnlists({cols:2,colWidth:0,equalHeight:false,startN:1});
Example
Columnize / Uncolumnize (equalHeight: ‘ol’)
-
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-
Cras vitae libero. Duis sed pede id erat laoreet varius.
-
Ut arcu mauris, blandit at, porttitor vel, scelerisque vitae, nunc.
-
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-
Cras vitae libero. Duis sed pede id erat laoreet varius.
-
Ut arcu mauris, blandit at, porttitor vel, scelerisque vitae, nunc.
-
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-
Cras vitae libero. Duis sed pede id erat laoreet varius.
-
Ut arcu mauris, blandit at, porttitor vel, scelerisque vitae, nunc.
Sourcecode
/** # * Copyright (c) 2008 Pasyuk Sergey (www.codeasily.com) # * Licensed under the MIT License: # * http://www.opensource.org/licenses/mit-license.php # * # * Splits a <ul>/<ol>-list into equal-sized columns. # * # * Requirements: # * <ul> # * <li>"ul" or "ol" element must be styled with margin</li> # * </ul> # * # * @see http://www.codeasily.com/jquery/multi-column-list-with-jquery # */ jQuery.fn.makeacolumnlists = function(settings){ settings = jQuery.extend({ cols: 3, // set number of columns colWidth: 0, // set width for each column or leave 0 for auto width equalHeight: false, // can be false, 'ul', 'ol', 'li' startN: 1 // first number on your ordered list }, settings); if(jQuery('> li', this)) { this.each(function(y) { var y=jQuery('.li_container').size(), height = 0, maxHeight = 0, t = jQuery(this), classN = t.attr('class'), listsize = jQuery('> li', this).size(), percol = Math.ceil(listsize/settings.cols), contW = t.width(), bl = ( isNaN(parseInt(t.css('borderLeftWidth'),10)) ? 0 : parseInt(t.css('borderLeftWidth'),10) ), br = ( isNaN(parseInt(t.css('borderRightWidth'),10)) ? 0 : parseInt(t.css('borderRightWidth'),10) ), pl = parseInt(t.css('paddingLeft'),10), pr = parseInt(t.css('paddingRight'),10), ml = parseInt(t.css('marginLeft'),10), mr = parseInt(t.css('marginRight'),10), col_Width = Math.floor((contW - (settings.cols-1)*(bl+br+pl+pr+ml+mr))/settings.cols); if (settings.colWidth) { col_Width = settings.colWidth; } var colnum=1, percol2=percol; jQuery(this).addClass('li_cont1').wrap('<div id="li_container' + (++y) + '" class="li_container"></div>'); if (settings.equalHeight=='li') { jQuery('> li', this).each(function() { var e = jQuery(this); var border_top = ( isNaN(parseInt(e.css('borderTopWidth'),10)) ? 0 : parseInt(e.css('borderTopWidth'),10) ); var border_bottom = ( isNaN(parseInt(e.css('borderBottomWidth'),10)) ? 0 : parseInt(e.css('borderBottomWidth'),10) ); height = e.height() + parseInt(e.css('paddingTop'), 10) + parseInt(e.css('paddingBottom'), 10) + border_top + border_bottom; maxHeight = (height > maxHeight) ? height : maxHeight; }); } for (var i=0; i<=listsize; i++) { if(i>=percol2) { percol2+=percol; colnum++; } var eh = jQuery('> li:eq('+i+')',this); eh.addClass('li_col'+ colnum); if(jQuery(this).is('ol')){eh.attr('value', ''+(i+settings.startN))+'';} if (settings.equalHeight=='li') { var border_top = ( isNaN(parseInt(eh.css('borderTopWidth'),10)) ? 0 : parseInt(eh.css('borderTopWidth'),10) ); var border_bottom = ( isNaN(parseInt(eh.css('borderBottomWidth'),10)) ? 0 : parseInt(eh.css('borderBottomWidth'),10) ); mh = maxHeight - (parseInt(eh.css('paddingTop'), 10) + parseInt(eh.css('paddingBottom'), 10) + border_top + border_bottom ); eh.height(mh); } } jQuery(this).css({cssFloat:'left', width:''+col_Width+'px'}); for (colnum=2; colnum<=settings.cols; colnum++) { if(jQuery(this).is('ol')) { jQuery('li.li_col'+ colnum, this).appendTo('#li_container' + y).wrapAll('<ol class="li_cont'+colnum +' ' + classN + '" style="float:left; width: '+col_Width+'px;"></ol>'); } else { jQuery('li.li_col'+ colnum, this).appendTo('#li_container' + y).wrapAll('<ul class="li_cont'+colnum +' ' + classN + '" style="float:left; width: '+col_Width+'px;"></ul>'); } } if (settings.equalHeight=='ul' || settings.equalHeight=='ol') { for (colnum=1; colnum<=settings.cols; colnum++) { jQuery('#li_container'+ y +' .li_cont'+colnum).each(function() { var e = jQuery(this); var border_top = ( isNaN(parseInt(e.css('borderTopWidth'),10)) ? 0 : parseInt(e.css('borderTopWidth'),10) ); var border_bottom = ( isNaN(parseInt(e.css('borderBottomWidth'),10)) ? 0 : parseInt(e.css('borderBottomWidth'),10) ); height = e.height() + parseInt(e.css('paddingTop'), 10) + parseInt(e.css('paddingBottom'), 10) + border_top + border_bottom; maxHeight = (height > maxHeight) ? height : maxHeight; }); } for (colnum=1; colnum<=settings.cols; colnum++) { var eh = jQuery('#li_container'+ y +' .li_cont'+colnum); var border_top = ( isNaN(parseInt(eh.css('borderTopWidth'),10)) ? 0 : parseInt(eh.css('borderTopWidth'),10) ); var border_bottom = ( isNaN(parseInt(eh.css('borderBottomWidth'),10)) ? 0 : parseInt(eh.css('borderBottomWidth'),10) ); mh = maxHeight - (parseInt(eh.css('paddingTop'), 10) + parseInt(eh.css('paddingBottom'), 10) + border_top + border_bottom ); eh.height(mh); } } jQuery('#li_container' + y).append('<div style="clear:both; overflow:hidden; height:0px;"></div>'); }); } } jQuery.fn.uncolumnlists = function(){ jQuery('.li_cont1').each(function(i) { var onecolSize = jQuery('#li_container' + (++i) + ' .li_cont1 > li').size(); if(jQuery('#li_container' + i + ' .li_cont1').is('ul')) { jQuery('#li_container' + i + ' > ul > li').appendTo('#li_container' + i + ' ul:first'); for (var j=1; j<=onecolSize; j++) { jQuery('#li_container' + i + ' ul:first li').removeAttr('class').removeAttr('style'); } jQuery('#li_container' + i + ' ul:first').removeAttr('style').removeClass('li_cont1').insertBefore('#li_container' + i); } else { jQuery('#li_container' + i + ' > ol > li').appendTo('#li_container' + i + ' ol:first'); for (var j=1; j<=onecolSize; j++) { jQuery('#li_container' + i + ' ol:first li').removeAttr('class').removeAttr('style'); } jQuery('#li_container' + i + ' ol:first').removeAttr('style').removeClass('li_cont1').insertBefore('#li_container' + i); } jQuery('#li_container' + i).remove(); }); }
There are few parameters – cols, the number of columns to break the list into; colWidth set width for each column or leave 0 for auto width; equalHeight (defaulting to false) can be false, ‘ul’, ‘ol’, ‘li’ to set equal height for ul/ol or li elements; startN, the start number of numbered list.
I’ve tested with IE 6&7, FF3, Safari3 and Opera 9. The code could use a bit of refactoring perhaps for the purpose of beautification. View my demo file to see more samples or download
I’ve added this to the jQuery Plugin site.