PageSourceSearch

https://gartenhotel.com/fileadmin/template/javascript/desktop/jquery.columnizer.js?1392185143

js gartenhotel.com collected 2026-10-02 10:43:43 UTC 21,499 bytes, 610 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.