1 | // version 1.6.0 |
---|
2 | // http://welcome.totheinter.net/columnizer-jquery-plugin/ |
---|
3 | // created by: Adam Wulf @adamwulf, adam.wulf@gmail.com |
---|
4 | |
---|
5 | (function($){ |
---|
6 | |
---|
7 | $.fn.columnize = function(options) { |
---|
8 | |
---|
9 | |
---|
10 | var defaults = { |
---|
11 | // default width of columns |
---|
12 | width: 400, |
---|
13 | // optional # of columns instead of width |
---|
14 | columns : false, |
---|
15 | // true to build columns once regardless of window resize |
---|
16 | // false to rebuild when content box changes bounds |
---|
17 | buildOnce : false, |
---|
18 | // an object with options if the text should overflow |
---|
19 | // it's container if it can't fit within a specified height |
---|
20 | overflow : false, |
---|
21 | // this function is called after content is columnized |
---|
22 | doneFunc : function(){}, |
---|
23 | // if the content should be columnized into a |
---|
24 | // container node other than it's own node |
---|
25 | target : false, |
---|
26 | // re-columnizing when images reload might make things |
---|
27 | // run slow. so flip this to true if it's causing delays |
---|
28 | ignoreImageLoading : true, |
---|
29 | // should columns float left or right |
---|
30 | columnFloat : "left", |
---|
31 | // ensure the last column is never the tallest column |
---|
32 | lastNeverTallest : false, |
---|
33 | // (int) the minimum number of characters to jump when splitting |
---|
34 | // text nodes. smaller numbers will result in higher accuracy |
---|
35 | // column widths, but will take slightly longer |
---|
36 | accuracy : false, |
---|
37 | // don't automatically layout columns, only use manual columnbreak |
---|
38 | manualBreaks : false, |
---|
39 | // previx for all the CSS classes used by this plugin |
---|
40 | // default to empty string for backwards compatibility |
---|
41 | cssClassPrefix : "" |
---|
42 | }; |
---|
43 | options = $.extend(defaults, options); |
---|
44 | |
---|
45 | if(typeof(options.width) == "string"){ |
---|
46 | options.width = parseInt(options.width,10); |
---|
47 | if(isNaN(options.width)){ |
---|
48 | options.width = defaults.width; |
---|
49 | } |
---|
50 | } |
---|
51 | |
---|
52 | /** |
---|
53 | * appending a text node to a <table> will |
---|
54 | * cause a jquery crash. |
---|
55 | * so wrap all append() calls and revert to |
---|
56 | * a simple appendChild() in case it fails |
---|
57 | */ |
---|
58 | function appendSafe($target, $elem){ |
---|
59 | try{ |
---|
60 | $target.append($elem); |
---|
61 | }catch(e){ |
---|
62 | $target[0].appendChild($elem[0]); |
---|
63 | } |
---|
64 | } |
---|
65 | |
---|
66 | return this.each(function() { |
---|
67 | var $inBox = options.target ? $(options.target) : $(this); |
---|
68 | var maxHeight = $(this).height(); |
---|
69 | var $cache = $('<div></div>'); // this is where we'll put the real content |
---|
70 | var lastWidth = 0; |
---|
71 | var columnizing = false; |
---|
72 | var manualBreaks = options.manualBreaks; |
---|
73 | var cssClassPrefix = defaults.cssClassPrefix; |
---|
74 | if(typeof(options.cssClassPrefix) == "string"){ |
---|
75 | cssClassPrefix = options.cssClassPrefix; |
---|
76 | } |
---|
77 | |
---|
78 | |
---|
79 | var adjustment = 0; |
---|
80 | |
---|
81 | appendSafe($cache, $(this).contents().clone(true)); |
---|
82 | |
---|
83 | // images loading after dom load |
---|
84 | // can screw up the column heights, |
---|
85 | // so recolumnize after images load |
---|
86 | if(!options.ignoreImageLoading && !options.target){ |
---|
87 | if(!$inBox.data("imageLoaded")){ |
---|
88 | $inBox.data("imageLoaded", true); |
---|
89 | if($(this).find("img").length > 0){ |
---|
90 | // only bother if there are |
---|
91 | // actually images... |
---|
92 | var func = function($inBox,$cache){ return function(){ |
---|
93 | if(!$inBox.data("firstImageLoaded")){ |
---|
94 | $inBox.data("firstImageLoaded", "true"); |
---|
95 | appendSafe($inBox.empty(), $cache.children().clone(true)); |
---|
96 | $inBox.columnize(options); |
---|
97 | } |
---|
98 | }; |
---|
99 | }($(this), $cache); |
---|
100 | $(this).find("img").one("load", func); |
---|
101 | $(this).find("img").one("abort", func); |
---|
102 | return; |
---|
103 | } |
---|
104 | } |
---|
105 | } |
---|
106 | |
---|
107 | $inBox.empty(); |
---|
108 | |
---|
109 | columnizeIt(); |
---|
110 | |
---|
111 | if(!options.buildOnce){ |
---|
112 | $(window).resize(function() { |
---|
113 | if(!options.buildOnce){ |
---|
114 | if($inBox.data("timeout")){ |
---|
115 | clearTimeout($inBox.data("timeout")); |
---|
116 | } |
---|
117 | $inBox.data("timeout", setTimeout(columnizeIt, 200)); |
---|
118 | } |
---|
119 | }); |
---|
120 | } |
---|
121 | |
---|
122 | function prefixTheClassName(className, withDot){ |
---|
123 | var dot = withDot ? "." : ""; |
---|
124 | if(cssClassPrefix.length){ |
---|
125 | return dot + cssClassPrefix + "-" + className; |
---|
126 | } |
---|
127 | return dot + className; |
---|
128 | } |
---|
129 | |
---|
130 | /** |
---|
131 | * this fuction builds as much of a column as it can without |
---|
132 | * splitting nodes in half. If the last node in the new column |
---|
133 | * is a text node, then it will try to split that text node. otherwise |
---|
134 | * it will leave the node in $pullOutHere and return with a height |
---|
135 | * smaller than targetHeight. |
---|
136 | * |
---|
137 | * Returns a boolean on whether we did some splitting successfully at a text point |
---|
138 | * (so we know we don't need to split a real element). return false if the caller should |
---|
139 | * split a node if possible to end this column. |
---|
140 | * |
---|
141 | * @param putInHere, the jquery node to put elements into for the current column |
---|
142 | * @param $pullOutHere, the jquery node to pull elements out of (uncolumnized html) |
---|
143 | * @param $parentColumn, the jquery node for the currently column that's being added to |
---|
144 | * @param targetHeight, the ideal height for the column, get as close as we can to this height |
---|
145 | */ |
---|
146 | function columnize($putInHere, $pullOutHere, $parentColumn, targetHeight){ |
---|
147 | // |
---|
148 | // add as many nodes to the column as we can, |
---|
149 | // but stop once our height is too tall |
---|
150 | while((manualBreaks || $parentColumn.height() < targetHeight) && |
---|
151 | $pullOutHere[0].childNodes.length){ |
---|
152 | var node = $pullOutHere[0].childNodes[0]; |
---|
153 | // |
---|
154 | // Because we're not cloning, jquery will actually move the element" |
---|
155 | // http://welcome.totheinter.net/2009/03/19/the-undocumented-life-of-jquerys-append/ |
---|
156 | if($(node).find(prefixTheClassName("columnbreak", true)).length){ |
---|
157 | // |
---|
158 | // our column is on a column break, so just end here |
---|
159 | return; |
---|
160 | } |
---|
161 | if($(node).hasClass(prefixTheClassName("columnbreak"))){ |
---|
162 | // |
---|
163 | // our column is on a column break, so just end here |
---|
164 | return; |
---|
165 | } |
---|
166 | appendSafe($putInHere, $(node)); |
---|
167 | } |
---|
168 | if($putInHere[0].childNodes.length === 0) return; |
---|
169 | |
---|
170 | // now we're too tall, so undo the last one |
---|
171 | var kids = $putInHere[0].childNodes; |
---|
172 | var lastKid = kids[kids.length-1]; |
---|
173 | $putInHere[0].removeChild(lastKid); |
---|
174 | var $item = $(lastKid); |
---|
175 | |
---|
176 | // now lets try to split that last node |
---|
177 | // to fit as much of it as we can into this column |
---|
178 | if($item[0].nodeType == 3){ |
---|
179 | // it's a text node, split it up |
---|
180 | var oText = $item[0].nodeValue; |
---|
181 | var counter2 = options.width / 18; |
---|
182 | if(options.accuracy) |
---|
183 | counter2 = options.accuracy; |
---|
184 | var columnText; |
---|
185 | var latestTextNode = null; |
---|
186 | while($parentColumn.height() < targetHeight && oText.length){ |
---|
187 | // |
---|
188 | // it's been brought up that this won't work for chinese |
---|
189 | // or other languages that don't have the same use of whitespace |
---|
190 | // as english. This will need to be updated in the future |
---|
191 | // to better handle non-english languages. |
---|
192 | // |
---|
193 | // https://github.com/adamwulf/Columnizer-jQuery-Plugin/issues/124 |
---|
194 | var indexOfSpace = oText.indexOf(' ', counter2); |
---|
195 | if (indexOfSpace != -1) { |
---|
196 | columnText = oText.substring(0, indexOfSpace); |
---|
197 | } else { |
---|
198 | columnText = oText; |
---|
199 | } |
---|
200 | latestTextNode = document.createTextNode(columnText); |
---|
201 | appendSafe($putInHere, $(latestTextNode)); |
---|
202 | |
---|
203 | if(oText.length > counter2 && indexOfSpace != -1){ |
---|
204 | oText = oText.substring(indexOfSpace); |
---|
205 | }else{ |
---|
206 | oText = ""; |
---|
207 | } |
---|
208 | } |
---|
209 | if($parentColumn.height() >= targetHeight && latestTextNode !== null){ |
---|
210 | // too tall :( |
---|
211 | $putInHere[0].removeChild(latestTextNode); |
---|
212 | oText = latestTextNode.nodeValue + oText; |
---|
213 | } |
---|
214 | if(oText.length){ |
---|
215 | $item[0].nodeValue = oText; |
---|
216 | }else{ |
---|
217 | return false; // we ate the whole text node, move on to the next node |
---|
218 | } |
---|
219 | } |
---|
220 | |
---|
221 | if($pullOutHere.contents().length){ |
---|
222 | $pullOutHere.prepend($item); |
---|
223 | }else{ |
---|
224 | appendSafe($pullOutHere, $item); |
---|
225 | } |
---|
226 | |
---|
227 | return $item[0].nodeType == 3; |
---|
228 | } |
---|
229 | |
---|
230 | /** |
---|
231 | * Split up an element, which is more complex than splitting text. We need to create |
---|
232 | * two copies of the element with it's contents divided between each |
---|
233 | */ |
---|
234 | function split($putInHere, $pullOutHere, $parentColumn, targetHeight){ |
---|
235 | if($putInHere.contents(":last").find(prefixTheClassName("columnbreak", true)).length){ |
---|
236 | // |
---|
237 | // our column is on a column break, so just end here |
---|
238 | return; |
---|
239 | } |
---|
240 | if($putInHere.contents(":last").hasClass(prefixTheClassName("columnbreak"))){ |
---|
241 | // |
---|
242 | // our column is on a column break, so just end here |
---|
243 | return; |
---|
244 | } |
---|
245 | if($pullOutHere.contents().length){ |
---|
246 | var $cloneMe = $pullOutHere.contents(":first"); |
---|
247 | // |
---|
248 | // make sure we're splitting an element |
---|
249 | if( typeof $cloneMe.get(0) == 'undefined' || $cloneMe.get(0).nodeType != 1 ) return; |
---|
250 | |
---|
251 | // |
---|
252 | // clone the node with all data and events |
---|
253 | var $clone = $cloneMe.clone(true); |
---|
254 | // |
---|
255 | // need to support both .prop and .attr if .prop doesn't exist. |
---|
256 | // this is for backwards compatibility with older versions of jquery. |
---|
257 | if($cloneMe.hasClass(prefixTheClassName("columnbreak"))){ |
---|
258 | // |
---|
259 | // ok, we have a columnbreak, so add it into |
---|
260 | // the column and exit |
---|
261 | appendSafe($putInHere, $clone); |
---|
262 | $cloneMe.remove(); |
---|
263 | }else if (manualBreaks){ |
---|
264 | // keep adding until we hit a manual break |
---|
265 | appendSafe($putInHere, $clone); |
---|
266 | $cloneMe.remove(); |
---|
267 | }else if($clone.get(0).nodeType == 1 && !$clone.hasClass(prefixTheClassName("dontend"))){ |
---|
268 | appendSafe($putInHere, $clone); |
---|
269 | if($clone.is("img") && $parentColumn.height() < targetHeight + 20){ |
---|
270 | // |
---|
271 | // we can't split an img in half, so just add it |
---|
272 | // to the column and remove it from the pullOutHere section |
---|
273 | $cloneMe.remove(); |
---|
274 | }else if($cloneMe.hasClass(prefixTheClassName("dontsplit")) && $parentColumn.height() < targetHeight + 20){ |
---|
275 | // |
---|
276 | // pretty close fit, and we're not allowed to split it, so just |
---|
277 | // add it to the column, remove from pullOutHere, and be done |
---|
278 | $cloneMe.remove(); |
---|
279 | }else if($clone.is("img") || $cloneMe.hasClass(prefixTheClassName("dontsplit"))){ |
---|
280 | // |
---|
281 | // it's either an image that's too tall, or an unsplittable node |
---|
282 | // that's too tall. leave it in the pullOutHere and we'll add it to the |
---|
283 | // next column |
---|
284 | $clone.remove(); |
---|
285 | }else{ |
---|
286 | // |
---|
287 | // ok, we're allowed to split the node in half, so empty out |
---|
288 | // the node in the column we're building, and start splitting |
---|
289 | // it in half, leaving some of it in pullOutHere |
---|
290 | $clone.empty(); |
---|
291 | if(!columnize($clone, $cloneMe, $parentColumn, targetHeight)){ |
---|
292 | // this node may still have non-text nodes to split |
---|
293 | // add the split class and then recur |
---|
294 | $cloneMe.addClass(prefixTheClassName("split")); |
---|
295 | |
---|
296 | //if this node was ol element, the child should continue the number ordering |
---|
297 | if($cloneMe.get(0).tagName == 'OL'){ |
---|
298 | var startWith = $clone.get(0).childElementCount + $clone.get(0).start; |
---|
299 | $cloneMe.attr('start',startWith+1); |
---|
300 | } |
---|
301 | |
---|
302 | if($cloneMe.children().length){ |
---|
303 | split($clone, $cloneMe, $parentColumn, targetHeight); |
---|
304 | } |
---|
305 | }else{ |
---|
306 | // this node only has text node children left, add the |
---|
307 | // split class and move on. |
---|
308 | $cloneMe.addClass(prefixTheClassName("split")); |
---|
309 | } |
---|
310 | if($clone.get(0).childNodes.length === 0){ |
---|
311 | // it was split, but nothing is in it :( |
---|
312 | $clone.remove(); |
---|
313 | $cloneMe.removeClass(prefixTheClassName("split")); |
---|
314 | } |
---|
315 | } |
---|
316 | } |
---|
317 | } |
---|
318 | } |
---|
319 | |
---|
320 | |
---|
321 | function singleColumnizeIt() { |
---|
322 | if ($inBox.data("columnized") && $inBox.children().length == 1) { |
---|
323 | return; |
---|
324 | } |
---|
325 | $inBox.data("columnized", true); |
---|
326 | $inBox.data("columnizing", true); |
---|
327 | |
---|
328 | $inBox.empty(); |
---|
329 | $inBox.append($("<div class='" |
---|
330 | + prefixTheClassName("first") + " " |
---|
331 | + prefixTheClassName("last") + " " |
---|
332 | + prefixTheClassName("column") + " " |
---|
333 | + "' style='width:100%; float: " + options.columnFloat + ";'></div>")); //" |
---|
334 | $col = $inBox.children().eq($inBox.children().length-1); |
---|
335 | $destroyable = $cache.clone(true); |
---|
336 | if(options.overflow){ |
---|
337 | targetHeight = options.overflow.height; |
---|
338 | columnize($col, $destroyable, $col, targetHeight); |
---|
339 | // make sure that the last item in the column isn't a "dontend" |
---|
340 | if(!$destroyable.contents().find(":first-child").hasClass(prefixTheClassName("dontend"))){ |
---|
341 | split($col, $destroyable, $col, targetHeight); |
---|
342 | } |
---|
343 | |
---|
344 | while($col.contents(":last").length && checkDontEndColumn($col.contents(":last").get(0))){ |
---|
345 | var $lastKid = $col.contents(":last"); |
---|
346 | $lastKid.remove(); |
---|
347 | $destroyable.prepend($lastKid); |
---|
348 | } |
---|
349 | |
---|
350 | var html = ""; |
---|
351 | var div = document.createElement('DIV'); |
---|
352 | while($destroyable[0].childNodes.length > 0){ |
---|
353 | var kid = $destroyable[0].childNodes[0]; |
---|
354 | if(kid.attributes){ |
---|
355 | for(var i=0;i<kid.attributes.length;i++){ |
---|
356 | if(kid.attributes[i].nodeName.indexOf("jQuery") === 0){ |
---|
357 | kid.removeAttribute(kid.attributes[i].nodeName); |
---|
358 | } |
---|
359 | } |
---|
360 | } |
---|
361 | div.innerHTML = ""; |
---|
362 | div.appendChild($destroyable[0].childNodes[0]); |
---|
363 | html += div.innerHTML; |
---|
364 | } |
---|
365 | var overflow = $(options.overflow.id)[0]; |
---|
366 | overflow.innerHTML = html; |
---|
367 | |
---|
368 | }else{ |
---|
369 | appendSafe($col, $destroyable.contents()); |
---|
370 | } |
---|
371 | $inBox.data("columnizing", false); |
---|
372 | |
---|
373 | if(options.overflow && options.overflow.doneFunc){ |
---|
374 | options.overflow.doneFunc(); |
---|
375 | } |
---|
376 | |
---|
377 | } |
---|
378 | |
---|
379 | /** |
---|
380 | * returns true if the input dom node |
---|
381 | * should not end a column. |
---|
382 | * returns false otherwise |
---|
383 | */ |
---|
384 | function checkDontEndColumn(dom){ |
---|
385 | if(dom.nodeType == 3){ |
---|
386 | // text node. ensure that the text |
---|
387 | // is not 100% whitespace |
---|
388 | if(/^\s+$/.test(dom.nodeValue)){ |
---|
389 | // |
---|
390 | // ok, it's 100% whitespace, |
---|
391 | // so we should return checkDontEndColumn |
---|
392 | // of the inputs previousSibling |
---|
393 | if(!dom.previousSibling) return false; |
---|
394 | return checkDontEndColumn(dom.previousSibling); |
---|
395 | } |
---|
396 | return false; |
---|
397 | } |
---|
398 | if(dom.nodeType != 1) return false; |
---|
399 | if($(dom).hasClass(prefixTheClassName("dontend"))) return true; |
---|
400 | if(dom.childNodes.length === 0) return false; |
---|
401 | return checkDontEndColumn(dom.childNodes[dom.childNodes.length-1]); |
---|
402 | } |
---|
403 | |
---|
404 | function columnizeIt() { |
---|
405 | //reset adjustment var |
---|
406 | adjustment = 0; |
---|
407 | if(lastWidth == $inBox.width()) return; |
---|
408 | lastWidth = $inBox.width(); |
---|
409 | |
---|
410 | var numCols = Math.round($inBox.width() / options.width); |
---|
411 | var optionWidth = options.width; |
---|
412 | var optionHeight = options.height; |
---|
413 | if(options.columns) numCols = options.columns; |
---|
414 | if(manualBreaks){ |
---|
415 | numCols = $cache.find(prefixTheClassName("columnbreak", true)).length + 1; |
---|
416 | optionWidth = false; |
---|
417 | } |
---|
418 | |
---|
419 | // if ($inBox.data("columnized") && numCols == $inBox.children().length) { |
---|
420 | // return; |
---|
421 | // } |
---|
422 | if(numCols <= 1){ |
---|
423 | return singleColumnizeIt(); |
---|
424 | } |
---|
425 | if($inBox.data("columnizing")) return; |
---|
426 | $inBox.data("columnized", true); |
---|
427 | $inBox.data("columnizing", true); |
---|
428 | |
---|
429 | $inBox.empty(); |
---|
430 | $inBox.append($("<div style='width:" + (Math.floor(100 / numCols))+ "%; float: " + options.columnFloat + ";'></div>")); //" |
---|
431 | $col = $inBox.children(":last"); |
---|
432 | appendSafe($col, $cache.clone()); |
---|
433 | maxHeight = $col.height(); |
---|
434 | $inBox.empty(); |
---|
435 | |
---|
436 | var targetHeight = maxHeight / numCols; |
---|
437 | var firstTime = true; |
---|
438 | var maxLoops = 3; |
---|
439 | var scrollHorizontally = false; |
---|
440 | if(options.overflow){ |
---|
441 | maxLoops = 1; |
---|
442 | targetHeight = options.overflow.height; |
---|
443 | }else if(optionHeight && optionWidth){ |
---|
444 | maxLoops = 1; |
---|
445 | targetHeight = optionHeight; |
---|
446 | scrollHorizontally = true; |
---|
447 | } |
---|
448 | |
---|
449 | // |
---|
450 | // We loop as we try and workout a good height to use. We know it initially as an average |
---|
451 | // but if the last column is higher than the first ones (which can happen, depending on split |
---|
452 | // points) we need to raise 'adjustment'. We try this over a few iterations until we're 'solid'. |
---|
453 | // |
---|
454 | // also, lets hard code the max loops to 20. that's /a lot/ of loops for columnizer, |
---|
455 | // and should keep run aways in check. if somehow someone has content combined with |
---|
456 | // options that would cause an infinite loop, then this'll definitely stop it. |
---|
457 | for(var loopCount=0;loopCount<maxLoops && loopCount<20;loopCount++){ |
---|
458 | $inBox.empty(); |
---|
459 | var $destroyable, className, $col, $lastKid; |
---|
460 | try{ |
---|
461 | $destroyable = $cache.clone(true); |
---|
462 | }catch(e){ |
---|
463 | // jquery in ie6 can't clone with true |
---|
464 | $destroyable = $cache.clone(); |
---|
465 | } |
---|
466 | $destroyable.css("visibility", "hidden"); |
---|
467 | // create the columns |
---|
468 | for (var i = 0; i < numCols; i++) { |
---|
469 | /* create column */ |
---|
470 | className = (i === 0) ? prefixTheClassName("first") : ""; |
---|
471 | className += " " + prefixTheClassName("column"); |
---|
472 | className = (i == numCols - 1) ? (prefixTheClassName("last") + " " + className) : className; |
---|
473 | $inBox.append($("<div class='" + className + "' style='width:" + (Math.floor(100 / numCols))+ "%; float: " + options.columnFloat + ";'></div>")); //" |
---|
474 | } |
---|
475 | |
---|
476 | // fill all but the last column (unless overflowing) |
---|
477 | i = 0; |
---|
478 | while(i < numCols - (options.overflow ? 0 : 1) || scrollHorizontally && $destroyable.contents().length){ |
---|
479 | if($inBox.children().length <= i){ |
---|
480 | // we ran out of columns, make another |
---|
481 | $inBox.append($("<div class='" + className + "' style='width:" + (Math.floor(100 / numCols))+ "%; float: " + options.columnFloat + ";'></div>")); //" |
---|
482 | } |
---|
483 | $col = $inBox.children().eq(i); |
---|
484 | if(scrollHorizontally){ |
---|
485 | $col.width(optionWidth + "px"); |
---|
486 | } |
---|
487 | columnize($col, $destroyable, $col, targetHeight); |
---|
488 | // make sure that the last item in the column isn't a "dontend" |
---|
489 | split($col, $destroyable, $col, targetHeight); |
---|
490 | |
---|
491 | while($col.contents(":last").length && checkDontEndColumn($col.contents(":last").get(0))){ |
---|
492 | $lastKid = $col.contents(":last"); |
---|
493 | $lastKid.remove(); |
---|
494 | $destroyable.prepend($lastKid); |
---|
495 | } |
---|
496 | i++; |
---|
497 | |
---|
498 | // |
---|
499 | // https://github.com/adamwulf/Columnizer-jQuery-Plugin/issues/47 |
---|
500 | // |
---|
501 | // check for infinite loop. |
---|
502 | // |
---|
503 | // this could happen when a dontsplit or dontend item is taller than the column |
---|
504 | // we're trying to build, and its never actually added to a column. |
---|
505 | // |
---|
506 | // this results in empty columns being added with the dontsplit item |
---|
507 | // perpetually waiting to get put into a column. lets force the issue here |
---|
508 | if($col.contents().length === 0 && $destroyable.contents().length){ |
---|
509 | // |
---|
510 | // ok, we're building zero content columns. this'll happen forever |
---|
511 | // since nothing can ever get taken out of destroyable. |
---|
512 | // |
---|
513 | // to fix, lets put 1 item from destroyable into the empty column |
---|
514 | // before we iterate |
---|
515 | $col.append($destroyable.contents(":first")); |
---|
516 | }else if(i == numCols - (options.overflow ? 0 : 1) && !options.overflow){ |
---|
517 | // |
---|
518 | // ok, we're about to exit the while loop because we're done with all |
---|
519 | // columns except the last column. |
---|
520 | // |
---|
521 | // if $destroyable still has columnbreak nodes in it, then we need to keep |
---|
522 | // looping and creating more columns. |
---|
523 | if($destroyable.find(prefixTheClassName("columnbreak", true)).length){ |
---|
524 | numCols ++; |
---|
525 | } |
---|
526 | } |
---|
527 | } |
---|
528 | if(options.overflow && !scrollHorizontally){ |
---|
529 | var IE6 = false /*@cc_on || @_jscript_version < 5.7 @*/; |
---|
530 | var IE7 = (document.all) && (navigator.appVersion.indexOf("MSIE 7.") != -1); |
---|
531 | if(IE6 || IE7){ |
---|
532 | var html = ""; |
---|
533 | var div = document.createElement('DIV'); |
---|
534 | while($destroyable[0].childNodes.length > 0){ |
---|
535 | var kid = $destroyable[0].childNodes[0]; |
---|
536 | for(i=0;i<kid.attributes.length;i++){ |
---|
537 | if(kid.attributes[i].nodeName.indexOf("jQuery") === 0){ |
---|
538 | kid.removeAttribute(kid.attributes[i].nodeName); |
---|
539 | } |
---|
540 | } |
---|
541 | div.innerHTML = ""; |
---|
542 | div.appendChild($destroyable[0].childNodes[0]); |
---|
543 | html += div.innerHTML; |
---|
544 | } |
---|
545 | var overflow = $(options.overflow.id)[0]; |
---|
546 | overflow.innerHTML = html; |
---|
547 | }else{ |
---|
548 | $(options.overflow.id).empty().append($destroyable.contents().clone(true)); |
---|
549 | } |
---|
550 | }else if(!scrollHorizontally){ |
---|
551 | // the last column in the series |
---|
552 | $col = $inBox.children().eq($inBox.children().length-1); |
---|
553 | $destroyable.contents().each( function() { |
---|
554 | $col.append( $(this) ); |
---|
555 | }); |
---|
556 | var afterH = $col.height(); |
---|
557 | var diff = afterH - targetHeight; |
---|
558 | var totalH = 0; |
---|
559 | var min = 10000000; |
---|
560 | var max = 0; |
---|
561 | var lastIsMax = false; |
---|
562 | var numberOfColumnsThatDontEndInAColumnBreak = 0; |
---|
563 | $inBox.children().each(function($inBox){ return function($item){ |
---|
564 | var $col = $inBox.children().eq($item); |
---|
565 | var endsInBreak = $col.children(":last").find(prefixTheClassName("columnbreak", true)).length; |
---|
566 | if(!endsInBreak){ |
---|
567 | var h = $col.height(); |
---|
568 | lastIsMax = false; |
---|
569 | totalH += h; |
---|
570 | if(h > max) { |
---|
571 | max = h; |
---|
572 | lastIsMax = true; |
---|
573 | } |
---|
574 | if(h < min) min = h; |
---|
575 | numberOfColumnsThatDontEndInAColumnBreak++; |
---|
576 | } |
---|
577 | }; |
---|
578 | }($inBox)); |
---|
579 | |
---|
580 | var avgH = totalH / numberOfColumnsThatDontEndInAColumnBreak; |
---|
581 | if(totalH === 0){ |
---|
582 | // |
---|
583 | // all columns end in a column break, |
---|
584 | // so we're done here |
---|
585 | loopCount = maxLoops; |
---|
586 | }else if(options.lastNeverTallest && lastIsMax){ |
---|
587 | // the last column is the tallest |
---|
588 | // so allow columns to be taller |
---|
589 | // and retry |
---|
590 | // |
---|
591 | // hopefully this'll mean more content fits into |
---|
592 | // earlier columns, so that the last column |
---|
593 | // can be shorter than the rest |
---|
594 | adjustment += 5; |
---|
595 | |
---|
596 | targetHeight = targetHeight + 30; |
---|
597 | if(loopCount == maxLoops-1) maxLoops++; |
---|
598 | }else if(max - min > 30){ |
---|
599 | // too much variation, try again |
---|
600 | targetHeight = avgH + 30; |
---|
601 | }else if(Math.abs(avgH-targetHeight) > 20){ |
---|
602 | // too much variation, try again |
---|
603 | targetHeight = avgH; |
---|
604 | }else { |
---|
605 | // solid, we're done |
---|
606 | loopCount = maxLoops; |
---|
607 | } |
---|
608 | }else{ |
---|
609 | // it's scrolling horizontally, fix the width/classes of the columns |
---|
610 | $inBox.children().each(function(i){ |
---|
611 | $col = $inBox.children().eq(i); |
---|
612 | $col.width(optionWidth + "px"); |
---|
613 | if(i === 0){ |
---|
614 | $col.addClass(prefixTheClassName("first")); |
---|
615 | }else if(i==$inBox.children().length-1){ |
---|
616 | $col.addClass(prefixTheClassName("last")); |
---|
617 | }else{ |
---|
618 | $col.removeClass(prefixTheClassName("first")); |
---|
619 | $col.removeClass(prefixTheClassName("last")); |
---|
620 | } |
---|
621 | }); |
---|
622 | $inBox.width($inBox.children().length * optionWidth + "px"); |
---|
623 | } |
---|
624 | $inBox.append($("<br style='clear:both;'>")); |
---|
625 | } |
---|
626 | $inBox.find(prefixTheClassName("column", true)).find(":first" + prefixTheClassName("removeiffirst", true)).remove(); |
---|
627 | $inBox.find(prefixTheClassName("column", true)).find(':last' + prefixTheClassName("removeiflast", true)).remove(); |
---|
628 | $inBox.find(prefixTheClassName("split", true)).find(":first" + prefixTheClassName("removeiffirst", true)).remove(); |
---|
629 | $inBox.find(prefixTheClassName("split", true)).find(':last' + prefixTheClassName("removeiflast", true)).remove(); |
---|
630 | $inBox.data("columnizing", false); |
---|
631 | |
---|
632 | if(options.overflow){ |
---|
633 | options.overflow.doneFunc(); |
---|
634 | } |
---|
635 | options.doneFunc(); |
---|
636 | } |
---|
637 | }); |
---|
638 | }; |
---|
639 | })(jQuery); |
---|