//Some stuff needs to be maintained in a global variable. MultiColumnResizeTimer=null; MultiColumnList=null; var MultiColumnPadding = 10; function MultiColumnSettings() { this.extraHeight=20; //Add extra height to a column. Increase this if the last column 'sticks out' too much. this.minSplitHeight=0; //If the base column is smaller than minSplitHeight, the column does not split. this.minHeight=0; //Minimum height of a column this.readOnText=null; //Add the "read on" notice a the bottom of each column this.classNameScreen=null; //Set the classname of *container* of the rendered columns for screen-media. Use to differentiate between JS/non-JS base column widths. this.classNamePrint=null; //Set the classname of *container* of the rendered columns for print-media. (optional, may be null) this.numberOfColumns=null; //null: calculate number of columns based on minimum width. Number >0: use specified number of columns, always adapt width. } function MultiColumn(columnContainerIn,settingsIn) { //IE6 doesn't support HTMLElement prototyping. IE7 probably won't too. Let's aim for IE8! *sigh* //But thank you, www.quirksmode.org! this.getStyle= function (element,stylePropW3,stylePropIE) { var y = null; if (element.currentStyle) y = element.currentStyle[stylePropIE]; else if (window.getComputedStyle && document.defaultView.getComputedStyle(element,null)) { y = document.defaultView.getComputedStyle(element,null).getPropertyValue(stylePropW3); } return y; } this.generateColumns= function () { var i=0; var numColumns; //Obtain the base column. This column contains the original text. var baseColumn=this.columnContainer.getElementsByTagName('div').item(0); //Add a node with style: "clear: both;" to stretch the container-node. var clearingNode=document.createElement('span'); clearingNode.style.display="block"; clearingNode.style.clear="both"; clearingNode.style.zoom="1"; //yet another work-around for a certain obsolete browser. this.columnContainer.appendChild(clearingNode); //Use specified number of columns, or calculate number based on minimum width? if (this.settings.numberOfColumns!=null) { //Use specified number of columns numColumns=this.settings.numberOfColumns; } else { //Calculate the number of columns that can be added, based on width. numColumns=Math.floor(this.columnContainer.offsetWidth/(baseColumn.offsetWidth)); //baseColumn.getStyle('width') gives wrong value in Opera } //Calculate the available width for one column. var availableWidth=Math.floor((this.columnContainer.offsetWidth-10)/numColumns)-parseInt(this.getStyle(baseColumn,'padding-right','paddingRight'))-parseInt(this.getStyle(baseColumn,'padding-left','paddingLeft')); //Add new columns for (i=1;i 0 && i < columns.length-1) { appendedPadding = MultiColumnPadding * 2; currentColumn.style.paddingLeft = MultiColumnPadding + "px"; currentColumn.style.paddingRight = MultiColumnPadding + "px"; } else { appendedPadding = MultiColumnPadding; currentColumn.style.paddingLeft = MultiColumnPadding + "px"; } } //Cut/paste blocks from the baseColumn to the new columns, until the reached the minHeight. for (i=0;i, moving text from to * until the column height is less or equal to the target height. * * Preconditions: and are element nodes. */ this.processElement=function (source,dest) { var lastSourceChild; while (lastSourceChild=source.lastChild) { if (lastSourceChild.nodeType==1) { //Make a shalow clone copy of this element to the destination //node, to preserve styles and attributes. var newDest=lastSourceChild.cloneNode(false); dest.insertBefore(newDest,dest.firstChild); //recursively process this node. if (this.processElement(lastSourceChild,newDest)) { return true; } } else if (lastSourceChild.nodeType==3) { //Wrap this text node.. if (this.wrapTextNode(lastSourceChild,dest)) { //..and return when the target has been reached. return true; } } //This node has been cleaned out. Remove it. source.removeChild(lastSourceChild); } return false; } /** * Cuts words at the end of , until the column height * is less or equal to target-height. * Cut words are then placed into * * Preconditions: is a text node. is an element node. */ this.wrapTextNode=function (source,dest) { var sourceText=source.nodeValue; //Split the text at spaces. var sourceTextAray=sourceText.split(/\s/); var destTextArray=new Array(); //Keep removing words form the source until the column fits. while (this.sourceColumn.offsetHeight>this.height && sourceTextAray.length>0) { destTextArray.push(sourceTextAray.pop()); source.nodeValue=sourceTextAray.join(' '); } //Add spaces at the front and end, if there are spaces in the original. var newText=(/^\s/.test(sourceText)?' ':'') + (destTextArray.reverse().join(' ')) + (/\s$/.test(sourceText)?' ':''); //Put the text into the destination node in the next column. dest.insertBefore(document.createTextNode(newText),dest.firstChild); //return true if the target has been reached. return this.sourceColumn.offsetHeight<=this.height; } //Duplicate the current paragraph by shallow copy destinationColumnIn.insertBefore(sourceParagraphIn.cloneNode(false),destinationColumnIn.firstChild); this.processElement(sourceParagraphIn,destinationColumnIn.firstChild); //check if the origal paragraph is emtpy if (sourceParagraphIn.offsetHeight==0) { //Check to see if normalized text is "" would be better.. //Yes it's empty. Remove the empty paragraph. this.sourceColumn.removeChild(sourceParagraphIn); } } function ListWrapper(sourceColumnIn, sourceListIn, destinationColumnIn, heightIn) { //Duplicate the current paragraph by shallow copy var newList=sourceListIn.cloneNode(false); destinationColumnIn.insertBefore(newList,destinationColumnIn.firstChild); //Loop over all elements in this list. while (currentElement=sourceListIn.lastChild) { if (sourceColumnIn.offsetHeight<=heightIn) { break; } if (currentElement.nodeName.toLowerCase()=='li') { newList.insertBefore(currentElement,newList.firstChild); } else { //remove the last element. sourceListIn.removeChild(currentElement); } } //Count current number of items. var numItems=1; var elementList=sourceListIn.childNodes; //count remaining items. for (var i=0;i