HEX
Server: Apache
System: Linux webm005.cluster121.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User: adventp (418412)
PHP: 7.4.33
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/adventp/www/wp-content/plugins/ut-portfolio/assets/js/jquery.isotope.perfectmasonry.js
/*!
 * PerfectMasonry extension for Isotope
 *
 * Does similar things as the Isotopes "masonry" layoutmode, except that this one will actually go back and plug the holes
 * left by bigger elements, thus making a perfect brick wall. Profit!
 * 
 * Usage:
 * 	$('#grid').isotope({
 * 		layoutMode: 'perfectMasonry',
 *		perfectMasonry: {
 *			layout: 'horizontal',		// Set layout as vertical/horizontal (default: vertical)
 *			columnWidth: 200,			// Set/Prefer columns to x wide (default: width of first tile)
 *			rowHeight: 200,				// Set/Prefer rows to y high (default: height of first tile)
 * 
 *			liquid: true,				// Set layout as liquid (default: false)
 *			cols: 3,					// Force to have x columns (default: null)
 *			rows: 3,					// Force to have y rows (default: null)
 *			minCols: 3,					// Set min col count (default: 1)
 *			minRows: 3,					// Set min row count (default: 1)
 *			maxCols: 5,					// Set max col count (default: 9999)
 *			maxRows: 4					// Set max row count (default: 9999)
 * 		}
 * 	});
 *
 * 
 * @author Mikko Tikkanen, Zonear Ltd. <contact@zonear.com>
 */
;(function($, undefined) {
	var version = '1.2.1';
	var isotope = null,
		$context = null,
		$container = null,
		isFirstRun = true;
	
	$.extend($.Isotope.prototype, {

		/**
		 * Reset layout properties
		 *
		 * Runs before any layout change
		 * -------------------------------------------------------------------------------------------------------- */
		_perfectMasonryReset: function() {
			var isVertical = this.options.perfectMasonry.layout != 'horizontal',
				isLiquid = this.options.perfectMasonry.liquid == true;
			
			// Do things on a first run
			if(isFirstRun) {
				isFirstRun = false;
				isotope = this;
				$context = $(this.element.context);
				$container = $context.parent();
				
				// Make sure we have min/maxCols & rows
				this.options.perfectMasonry.minCols = this.options.perfectMasonry.minCols || 1; 
				this.options.perfectMasonry.minRows = this.options.perfectMasonry.minRows || 1;
				this.options.perfectMasonry.maxCols = this.options.perfectMasonry.maxCols || 9999; 
				this.options.perfectMasonry.maxRows = this.options.perfectMasonry.maxRows || 9999;
			}
			
			// For liquid layout, replace default resize handler with forced relayout (outside firstRun as Isotope grid can be destroyed and created on the fly)
			if(isLiquid && $._data(window, 'events').smartresize) {
				$(window).off('smartresize.isotope');
				$(window).on('resize.isotope.perfectmasonry', function() {
					if(!$context.hasClass('isotope')) { return; }
					$context.isotope('reLayout');
				});
			}
			
			// Setup layout properties ---------------------------------------------------
			var properties = this.perfectMasonry = {};
			
			// Fill properties with columnWidth and rowHeight (true argument)
			this._getSegments();
      		this._getSegments(true);
      		
      		// ...and with cols & rows
			this._perfectMasonryGetSegments();
      		
			// Handle liquid layout (cols, rows & sizes must be calculated on the fly)
			if(isLiquid) {
				var width = $container.width(),
					height = $container.height();
					
				// Make sure we have colwidth & rowheight (get it from the calculated )
				this.options.perfectMasonry.columnWidth = this.options.perfectMasonry.columnWidth || properties.columnWidth;
				this.options.perfectMasonry.rowHeight = this.options.perfectMasonry.rowHeight || properties.rowHeight;
				
				// Figure out how many cols & rows either have been set or can be fit into the container (also make sure we're still between min/max)
				properties.cols = this.options.perfectMasonry.cols || Math.floor(width / this.options.perfectMasonry.columnWidth);
				properties.rows = this.options.perfectMasonry.rows || Math.floor(height / this.options.perfectMasonry.rowHeight);
				properties.cols = Math.min(Math.max(properties.cols, this.options.perfectMasonry.minCols), this.options.perfectMasonry.maxCols);
				properties.rows = Math.min(Math.max(properties.rows, this.options.perfectMasonry.minRows), this.options.perfectMasonry.maxRows);
								
				// Recalculate accurate width/height so that the whole available space is used
				var diff = (isVertical ? properties.columnWidth / (width / properties.cols) : properties.rowHeight / (height / properties.rows));
				properties.columnWidth = Math.floor(properties.columnWidth / diff);
				properties.rowHeight = Math.floor(properties.rowHeight / diff);
			}
			
			// Create top row of the grid
			properties.grid = new Array(this.perfectMasonry.cols);

			// Set container dimensions to 0
			properties.containerHeight = 0;
			properties.containerWidth = 0;
	    },



	    /**
		 * Create layout
		 * -------------------------------------------------------------------------------------------------------- */
		_perfectMasonryLayout: function($elems) {
			var instance = this,
				properties = this.perfectMasonry,
				isVertical = instance.options.perfectMasonry.layout != 'horizontal',
				isLiquid = instance.options.perfectMasonry.liquid == true;
			
			// Create first set of the grid
			properties.grid = new Array(properties[(isVertical ? 'cols' : 'rows')]);
			
			// Loop each element
			$elems.each(function() {
				var $this  = $(this);
				
				// Calculate col & row spans (with liquid layouts, store desired width as element data)
				var colSpan = (isLiquid ? $this.data('colSpan') : Math.ceil($this.outerWidth() / (properties.columnWidth + 1))),
					rowSpan = (isLiquid ? $this.data('rowSpan') : Math.ceil($this.outerHeight() / (properties.rowHeight + 1)));
				
				// For the first run with liquid layout, calculate sizes
				if(!colSpan) {
					colSpan = Math.ceil($this.outerWidth(true) / (properties.columnWidth + 1));
					rowSpan = Math.ceil($this.outerHeight(true) / (properties.rowHeight + 1));
					$this.data('colSpan', colSpan);
					$this.data('rowSpan', rowSpan);
				}
				
				
				/* Do the layout
				 * -------------------------------------------------------------------------------- */
				
				// Set spans
				var aSpan = (isVertical ? colSpan : rowSpan);
				var bSpan = (isVertical ? rowSpan : colSpan);
				
				// Bigger tiles can't fit into the last primary (though keep it still at least as 1)
				var max = Math.max((isVertical ? properties.cols - colSpan : properties.rows - rowSpan) + 1, 1);
								
				// Loop through/create primaries (set hard limit of 10.000 to prevent endless loop)
				var a = -1, x = 0, y = 0;
				while(++a < 10000) {
					properties.grid[a] = properties.grid[a] || [];
					
					// Go through the secondaries in the primary, set secondary and tile
					for (var b = 0; b < max; b++) {
						var tile = properties.grid[a][b];
							
						// If the tile is not free, move to the next one immediately
						if(tile) { continue; }

						// Tiles spanning to multiple rows/columns - Check if it'll fit
						var doesFit = true;
						if(colSpan > 1 || rowSpan > 1) {
							for (var i = 0; i < aSpan; i++) {
								for (var j = 0; j < bSpan; j++) {
									properties.grid[a+j] = properties.grid[a+j] || [];
									if(properties.grid[a+j][b+i]) { doesFit = false; break; }
								}

								// If it doesn't fit, don't waste our time looping
								if(!doesFit) { break; }
							}
						}
						if(!doesFit) { continue }
						

						// Set all the cells as occupied
						for (var i = 0; i < aSpan; i++) {
							for (var j = 0; j < bSpan; j++) {
								properties.grid[a+j][b+i] = true;
							}
						}
						
						// Set x & y values
						var x = a, y = b;
						if(isVertical) { var x = b, y = a; }
						
						// Update container dimensions
						properties.containerWidth = Math.max(properties.containerWidth, (x + aSpan) * properties.columnWidth);
						properties.containerHeight = Math.max(properties.containerHeight, (y + bSpan) * properties.rowHeight);
						
						// In case of liquid layout, set element size full width/height
						if(instance.options.perfectMasonry.liquid == true) {
							$this.css({
								width: properties.columnWidth * colSpan,
								height: properties.rowHeight * rowSpan
							});
						}

						// Set the element location and GTFO
						instance._pushPosition($this, x*properties.columnWidth, y*properties.rowHeight);
						return;
					}
				}
				

				// If we got all the way down to here, the element doesn't fit - Hide it
				instance._pushPosition($this, -9999, -9999);
			});
		},
		
		
		
	    /**
		 * Get container size
		 *
		 * For resizing the container
		 * -------------------------------------------------------------------------------------------------------- */
	    _perfectMasonryGetContainerSize: function() {
			return {
				width: this.perfectMasonry.containerWidth,
				height: this.perfectMasonry.containerHeight
			};
	    },
		
		
		
	    /**
		 * Resize changed
		 *
		 * Figure out if layout changed
		 * -------------------------------------------------------------------------------------------------------- */
	    _perfectMasonryResizeChanged: function() {
	    	var properties = this.perfectMasonry;

	    	// Store old values and calculate new numbers
	    	var oldCols = properties.cols,
	    		oldRows = properties.rows;
	    	this._perfectMasonryGetSegments();
			
			// If new count was different, force layout change
			if(this.options.perfectMasonry.layout == 'horizontal' && oldRows !== properties.rows) { return true; }
			if(oldCols !== properties.cols) { return true; }
			
	    	return false;
	    },
		
		
		
		
	    /**
		 * Private
		 * Do segment calculations by hand
		 * -------------------------------------------------------------------------------------------------------- */
		_perfectMasonryGetSegments: function() {
			var properties = this.perfectMasonry;
			var parent = this.options.perfectMasonry.parent || this.element.parent();
			
			// Calculate columns
			var parentWidth = parent.width();
			properties.cols = Math.floor(parentWidth / properties.columnWidth) || 1;

			// Calculate rows
			var parentHeight = parent.height();
			properties.rows = Math.floor(parentHeight / properties.rowHeight) || 1;
		}
	});
	
	
})(jQuery);