PageSourceSearch

https://buurtwerkplaatsnoorderhof.nl/_jsapps/_libs/cargo_plugins/columnizer.js

js buurtwerkplaatsnoorderhof.nl collected 2026-10-05 00:51:26 UTC 18,197 bytes, 657 lines download raw bytes

1// initialize and store reference in Cargo.Plugins
2var Cargo = Cargo || {};
3
4Cargo.Plugins = Cargo.Plugins || {};
5
6// use a closure so we have private and public methods.
7Cargo.Plugins.columnizer = (function($) { 
8		var self = {
9
10			vars: {
11				targets: {},
12				ticking: false,
13				init: true,
14				targetIndex: 0
15			},
16
17			options: {
18				'updateEvents': ['resize'],
19				fluid: true,
20				attributeConfig: {
21					'[data-columnize]' : {
22						role: 'initializer',
23						type: 'string'
24					}
25				}
26			},
27
28			init: function(){
29
30				// reqest ticks to make sure the update function only fires on animationFrames
31				$.each(self.options.updateEvents, function(key, event){
32					bindEvent(window, event, function(){
33						self.requestTick();
34					});
35				});
36
37				// stupid IE8 fallback
38				function bindEvent(el, eventName, eventHandler) {
39					if (el.addEventListener){
40						el.addEventListener(eventName, eventHandler, false); 
41					} else if (el.attachEvent){
42						el.attachEvent('on'+eventName, eventHandler);
43					}
44				}
45				
46				// update when (possibly) new content has been added
47				$(document).bind("paginationComplete", function(e) {  
48					self.updateTargets();
49				});
50
51				if(Cargo.hasOwnProperty('Event')){
52
53					Cargo.Event.on("inspector_preview", function() {
54						self.update(null, true);
55					});
56
57					Cargo.Event.on("inspector_open", function() {
58						self.addPaddingHelperListeners();
59						self.vars.inspector = true;
60					});
61
62					// Feed designs intervention
63					
64					var ignoreCollectionResets = false;
65					
66					if(Cargo.View.Feed !== undefined) {
67						
68						ignoreCollectionResets = true;
69
70						Cargo.Event.on("first_project_collection_reset", function(){
71							ignoreCollectionResets = false;
72						});
73					}						
74					
75					Cargo.Event.on("project_collection_reset", function() {
76						
77						if(ignoreCollectionResets) {
78							return;
79						}
80
81						if(Cargo.View.Feed !== undefined) {
82							// Projects have been deleted and re-rendered. Clear our cache.
83							for(var key in self.vars.targets){
84								
85								if( self.vars.targets[key].container[0] === Cargo.View.Feed.el ){
86									
87									self.vars.targets[key].container.find('[data-columnized]').removeAttr('data-columnized');
88									self.vars.targets[key].children = [];
89									self.vars.targets[key].shouldUpdate = true;
90
91								}
92
93							}
94						}
95
96						setTimeout(function(){
97							self.updateTargets();
98						});
99
100					});
101
102					Cargo.Event.on("project_load_complete", function(pid) {
103						self.updateTargets();
104					});
105				}
106
107				// initial check for targets.
108				self.updateTargets();
109				self.vars.init = false;
110			},
111
112			addPaddingHelperListeners: function(){
113				var children, evtManager = CargoInspector.eventManager;
114
115				for(key in self.vars.targets){
116					children = self.vars.targets[key].children;
117
118					for(var i = 0; i < children.length; i++){
119						if(children[i].hasPaddingHelper && children[i].hasPaddingHelperListener !== true){
120
121							(function(child){
122
123								evtManager.subscribe('style_changed', function(source){
124									
125									child.paddingChild.style.removeProperty('padding');
126
127									var styles = document.defaultView ? document.defaultView.getComputedStyle(child.paddingChild, null) : child.paddingChild.currentStyle;
128
129									child.paddingHelper.style.paddingLeft = styles.paddingLeft;
130									child.paddingHelper.style.paddingRight = styles.paddingRight;
131
132									child.paddingChild.style.paddingLeft = '0px';
133									child.paddingChild.style.paddingRight = '0px';
134								
135								});
136
137								child.hasPaddingHelperListener = true;
138
139							})(children[i]);
140						}
141					}
142				}
143			},
144
145			// we use animation frames. This requests an animationFrame and updates the plugin when the 
146			// animation frame has arrived. Only does this it once so we don't fire animationFrames 
147			// when the page is static
148			requestTick: function(){
149				if(!self.vars.ticking) {
150					requestAnimationFrame(self.update);
151					self.vars.ticking = true;
152				}
153			},
154
155			// check how many columns we can fit in the available space
156			updateAvailableColumnCounts: function(){
157				$.each(self.vars.targets, function(key, target){
158					var containerWidth = target.container.width();
159					var availableColumns = Math.floor(containerWidth / target.width);
160
161					if(target.fluid){
162						availableColumns += 1;
163					}
164
165					// don't make more columns than there are items to fill 'em with.
166					if(availableColumns > target.visibleElementCount && target.visibleElementCount !== 0){
167						availableColumns = target.visibleElementCount;
168					} else if(availableColumns < 1){
169						availableColumns = 1;
170					}
171					
172					target.availableColumns = availableColumns;
173
174					if(target.availableColumns != target.columnCount){
175						target.shouldUpdate = true;
176					}
177				});
178			},
179
180			randomize: function(targetSelector){
181				for(var key in self.vars.targets){
182					var target = self.vars.targets[key];
183					if(targetSelector !== undefined){
184						if(!target.container.is(targetSelector)){
185							continue;
186						}
187					}
188					shuffle(target.children);
189				};
190
191				self.update(null, true);
192
193				function shuffle(array) {
194					var currentIndex = array.length, temporaryValue, randomIndex;
195
196					// While there remain elements to shuffle...
197					while (0 !== currentIndex) {
198
199					// Pick a remaining element...
200					randomIndex = Math.floor(Math.random() * currentIndex);
201					currentIndex -= 1;
202
203					// And swap it with the current element.
204					temporaryValue = array[currentIndex];
205					array[currentIndex] = array[randomIndex];
206					array[randomIndex] = temporaryValue;
207					}
208
209					return array;
210				}
211			},
212
213			// updates all targets found in memory
214			// this thing should be all about speed so (almost) no jquery.
215			update: function(callback, force){
216				// check if there's a change in the amount of columns
217				self.updateAvailableColumnCounts();
218
219				for(var key in self.vars.targets){
220					var target = self.vars.targets[key];
221
222					if(target.children.length === 0) {
223						continue;
224					}
225
226					if(target.shouldUpdate || force){
227						target.container.find('.column').detach();
228						
229						// store everything in a fragement so nothing in the DOM is changed
230						// and no reflows/paints are triggered.
231						var frag = document.createDocumentFragment();
232						target.columnArr = [];
233
234						// Make the amount of columns
235						for (i = target.availableColumns; i > 0; i--) {
236							var col = document.createElement('div');
237
238							col.id = 'column_' + i;
239							col.className = 'column';
240							col.style.maxWidth = target.width + 'px';
241							col.style.display = 'inline-block';
242							col.style.verticalAlign = 'top';
243
244							// fluid columns need a percentage to scale width the browser width
245							if(target.fluid){
246								col.style.width = (100.0 / target.availableColumns) + '%';
247							} else {
248								col.style.width = target.width + 'px';
249							}
250
251							target.columnArr[i-1] = {
252								col: col,
253								height: 0
254							};
255						}
256
257						target.columnCount = target.columnArr.length;
258						target.shouldUpdate = false;
259
260						// offloaded this to a function so it can be called from updateTargets too.
261						self.addElementsToColumn(target, target.children);
262
263						// append the columns to the documentFragment
264						for(var i = 0; i < target.columnArr.length; i++){
265							frag.appendChild(target.columnArr[i].col);
266						}
267
268						// All done. Append the complete documentFragment to the DOM in one time.
269						target.container[0].appendChild(frag);
270
271						if(Cargo.Plugins.hasOwnProperty('elementResizer')){
272							Cargo.Plugins.elementResizer.update();
273						}
274						
275					}
276				};
277
278				self.vars.ticking = false;
279				
280				if(typeof callback == "function"){
281					callback();
282				}
283				
284				if(Cargo.hasOwnProperty('Event')){
285					Cargo.Event.trigger('columnizer_update_complete');
286				}
287			},
288
289			addElementsToColumn: function(target, children){
290				// add elements to columns.
291				if(target.availableColumns > 0){
292					for(var b = 0; b < children.length; b++){
293						// the column we're going to append the child to
294						var this_column;
295						
296						// This makes adding padding easy for end-users. They just have to 
297						// add padding to the children
298						if(!children[b].hasPaddingHelper){
299							$(children[b].element).find('img').each(function(){
300								this.style.maxWidth = this.getAttribute('width') + 'px';
301							});
302
303							var padding_helper = document.createElement("div");
304							padding_helper.className = "padding_helper";
305							
306							// switch the padding from child to helper
307							padding_helper.style.paddingLeft = target.padding_left + 'px';
308							padding_helper.style.paddingRight = target.padding_right + 'px';
309							children[b].element.style.paddingLeft = '0px';
310							children[b].element.style.paddingRight = '0px';
311							
312							// wrap element in helper
313							padding_helper.appendChild(children[b].element);
314							
315							// update the cached element
316							children[b].paddingChild = children[b].element;
317							children[b].element = padding_helper;
318							children[b].paddingHelper = padding_helper;
319							children[b].hasPaddingHelper = true;
320						}
321						
322						if(target.equalize){
323							// find the shortest column to append the child to
324							this_column = self.getShortestColumn(target);
325
326							// don't add any height if we have an invisible element
327							if(children[b].visible){
328								target.columnArr[this_column].height += (isNaN(children[b].lastUpdatedHeight) ? 1 : children[b].lastUpdatedHeight);
329							}
330						} else {
331							// just go from left to right
332							this_column = b % target.columnArr.length;
333						}
334
335						if(this_column >= 0){
336							target.columnArr[this_column].col.appendChild(children[b].element);
337						}
338					}
339				}
340			},
341
342			// Helper to figure out in what column we want to drop our next element
343			getShortestColumn: function(target) {
344
345				var lowest = 9e9,
346					lowestIndex = -1,
347					colHeight;
348
349				for(i = target.columnArr.length - 1; i > -1; i--){
350					colHeight = target.columnArr[i].height;
351					if(colHeight <= lowest){
352						lowestIndex = i;
353						lowest = colHeight;
354					}
355				}
356
357				return lowestIndex;
358
359			},
360
361			imagesLoaded: function(target, callback){
362
363				var incompleteImages = [];
364
365				if(target.nodeName == "IMG"){
366
367					if(target.complete === false){
368						incompleteImages.push(target);
369					}
370
371				} else {
372
373					$('img', target).each(function(){
374
375						/* Todo: Get rid of this */
376						if(this.getAttribute('src') === "/_gfx/thumb_custom.gif"){
377							this.style.maxHeight = this.getAttribute('height') + 'px';
378						}
379						
380						if(this.complete === false){
381							incompleteImages.push(this);
382						}
383
384					});
385
386				}
387
388				if(incompleteImages.length === 0){
389
390					// all images are done, callback.
391					typeof callback === "function" ? callback(0) : '';
392
393				} else {
394
395					// not all images are done. Install timers to listen for when they receive dimensions.
396					var i, completeImageCount = 0;
397
398					for(i = 0; i < incompleteImages.length; i++){
399
400						(function(img){
401
402							var ival;
403
404							ival = setInterval(function(){
405
406								if(img.naturalHeight !== 0 || img.complete){
407									
408									clearInterval(ival);
409
410									if(++completeImageCount === incompleteImages.length){
411										typeof callback === "function" ? callback(incompleteImages.length) : '';
412									}
413 
414								}
415
416							}, 30);
417
418						})(incompleteImages[i]);
419
420					}
421
422				}
423
424			},
425
426			updateTargets: function(){
427
428				var targets = $('[data-columnize]');
429
430				if(Cargo.hasOwnProperty('Event')){
431					Cargo.Event.trigger('columnizer_update_targets');
432				};
433
434				targets.each(function(key, target){
435
436					var $target		= $(target),
437						selector	= target.getAttribute('data-columnize'),
438						equalize	= (target.getAttribute('data-columnize-equalize') == "true" || target.getAttribute('data-columnize-mason') == "true" ? true : false),
439						children	= $target.find(selector).not('.padding_helper');
440
441					// get options stored in the target data attributes
442					var targetID 		= target.getAttribute('data-columnize-id'),
443						first_element 	= children.first(),
444						padding_left 	= parseInt(first_element.css('padding-left')),
445						padding_right 	= parseInt(first_element.css('padding-right')),
446						childrenArr 	= [],
447						targetObj;
448					
449					// make sure we get valid numbers
450					padding_left = (isNaN(padding_left) ? 0 : padding_left);
451					padding_right = (isNaN(padding_right) ? 0 : padding_right);
452					
453					var horizontal_padding = padding_right + padding_left; 		
454					
455					children.each(function(){
456
457						// only process if the element is new
458						if(this.getAttribute('data-columnized') != "1"){
459							// only process visible items
460							if($(this).is(':visible')){
461
462								var height = this.offsetHeight;
463
464								if(height < 1){
465									height = 1;
466								}
467								
468								// add processed child to the array
469								childrenArr.push({
470									element: this,
471									lastUpdatedHeight: height,
472									hasPaddingHelper: false
473								});
474
475								this.setAttribute('data-columnized', '1');
476							}
477						}
478
479					});
480
481					if (typeof targetID == 'undefined' || targetID == false || targetID == null || $target.find('.column').length == 0) {
482						
483						// hide while we're working
484						target.style.visibility = 'hidden';
485
486						// this element hasn't been seen before so we're gonna create a new object for it.
487						// also generating a new ID for later retrieval. 
488						targetID = ++self.vars.targetIndex;
489
490						// attach the ID to the element
491						$target.attr('data-columnize-id', targetID);
492
493						// create new object for this target
494						targetObj = {
495							container: $target,
496							selector: selector,
497							children: childrenArr,
498							columnCount: 0,
499							availableColumns: 0,
500							shouldUpdate: false,
501							padding_left: padding_left,
502							padding_right: padding_right,
503							fluid: (target.getAttribute('data-columnize-fluid') == "true" ? true : false),
504							width: (target.getAttribute('data-columnize-width') == "*" || isNaN(parseInt(target.getAttribute('data-columnize-width'))) || parseInt(target.getAttribute('data-columnize-width')) <= 0 ? 275 : parseInt(target.getAttribute('data-columnize-width')) + horizontal_padding),
505							equalize: equalize
506						};
507
508						// add it to the plugin's target list
509						self.vars.targets[targetID] = targetObj;
510
511					} else {
512
513						// element has already been processed before. Retrieve it by it's ID.
514						targetObj = self.vars.targets[targetID];
515
516						// update width & fluid
517						targetObj.fluid = (target.getAttribute('data-columnize-fluid') == "true" ? true : false);
518						targetObj.width = (target.getAttribute('data-columnize-width') == "*" || isNaN(parseInt(target.getAttribute('data-columnize-width'))) || parseInt(target.getAttribute('data-columnize-width')) <= 0 ? 275 : parseInt(target.getAttribute('data-columnize-width')) + (targetObj.padding_left + targetObj.padding_right));
519			
520						// concatenate the new children if any. 
521						if(children.length > 0){
522							targetObj.children = targetObj.children.concat(childrenArr);
523						}
524
525						// add the new children to the DOM.
526						self.addElementsToColumn(targetObj, childrenArr);
527
528					}
529
530					// check for hidden elements
531					var visibleElementCount = 0,
532						visible;
533
534					// TODO: this is expensive. Perhaps make an option to disable this if not needed
535					for(var i = 0; i < targetObj.children.length; i++){
536
537						if(!targetObj.children[i].hasPaddingHelper){
538							visible = $(targetObj.children[i].element).is(':visible');
539						} else {
540							// don't use padding_helper as the user shouldn't deal with that element
541							visible = $(targetObj.children[i].element).find(selector).is(':visible');
542						}
543
544						targetObj.children[i].visible = visible;
545
546						if(visible){
547							visibleElementCount++;
548						}
549
550					}
551
552					// we need to store how many elements are visible to calculate the required amount of columns.
553					targetObj.visibleElementCount = visibleElementCount;
554					
555					// check if we need to update.
556					self.update(function(){
557						// all done. Show the container.
558						target.style.visibility = 'visible';
559
560						if(Cargo.Plugins.hasOwnProperty('elementResizer')){
561							Cargo.Plugins.elementResizer.update();
562						}
563
564						var totalLoaded = 0,
565							height;
566
567						for(var i = 0; i < childrenArr.length; i++){
568							(function(childObj){
569
570								if(childObj.imagesLoadedStarted !== true){ 
571
572									self.imagesLoaded(childObj.element, function(){
573
574										height = childObj.element.clientHeight;
575
576										if(height < 1){
577											height = 1;
578										}
579
580										childObj.lastUpdatedHeight = height;
581
582										if(++totalLoaded === childrenArr.length){
583											self.update(undefined, true);
584										} else {
585											throttledUpdate();
586										}
587
588									});
589
590									childObj.imagesLoadedStarted = true;
591
592								}
593
594							})(childrenArr[i]);
595						};
596
597					}, true);
598
599
600				});
601
602				if(self.vars.inspector === true){
603					self.addPaddingHelperListeners();
604				}
605
606			}
607		};
608
609		var throttledUpdate = throttle(function (event) {
610								self.update(undefined, true);
611							  }, 100);
612
613		function throttle(fn, threshhold, scope) {
614			threshhold || (threshhold = 250);
615			var last,
616					deferTimer;
617			return function () {
618				var context = scope || this;
619
620				var now = +new Date,
621						args = arguments;
622				if (last && now < last + threshhold) {
623					// hold on to it
624					clearTimeout(deferTimer);
625					deferTimer = setTimeout(function () {
626						last = now;
627						fn.apply(context, args);
628					}, threshhold);
629				} else {
630					last = now;
631					fn.apply(context, args);
632				}
633			};
634		}
635
636		$(function(){ 
637			self.init();
638		});
639
640		// return some methods that should be public
641		return {
642			updateTargets: self.updateTargets,
643			update: self.update,
644			randomize: self.randomize,
645			getVars: function(){
646				return self.vars;
647			},
648			inspectorAPI: function(){
649				if(self.options.hasOwnProperty('attributeConfig')){
650					return self.options.attributeConfig;
651				} else {
652					// let the inspector know there's nothing to see here.
653					return false;
654				}
655			}
656		};
657})(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.