/*! * Masonry v3.1.1 * Cascading grid layout library * http://masonry.desandro.com * MIT License * by David DeSandro */ ( function( window ) { 'use strict'; // vars // var document = window.document; // -------------------------- helpers -------------------------- // var indexOf = Array.prototype.indexOf ? function( items, value ) { return items.indexOf( value ); } : function ( items, value ) { for ( var i=0, len = items.length; i < len; i++ ) { var item = items[i]; if ( item === value ) { return i; } } return -1; }; // -------------------------- masonryDefinition -------------------------- // // used for AMD definition and requires function masonryDefinition( layoutMode, getSize ) { // create an Outlayer layout class var Masonry = layoutMode.create('masonry'); Masonry.prototype._resetLayout = function() { this.isotope.getSize(); this._getMeasurement( 'columnWidth', 'outerWidth' ); this._getMeasurement( 'gutter', 'outerWidth' ); this.measureColumns(); // reset column Y var i = this.cols; this.colYs = []; while (i--) { this.colYs.push( 0 ); } this.maxY = 0; }; Masonry.prototype.measureColumns = function() { var container = this._getSizingContainer(); // if columnWidth is 0, default to outerWidth of first item var firstItem = this.items[0]; var firstItemElem = firstItem && firstItem.element; if ( !this.columnWidth ) { // columnWidth fall back to item of first element this.columnWidth = firstItemElem ? getSize( firstItemElem ).outerWidth : // or size of container this.size.innerWidth; } this.columnWidth += this.gutter; this._containerWidth = getSize( container ).innerWidth; this.cols = Math.floor( ( this._containerWidth + this.gutter ) / this.columnWidth ); this.cols = Math.max( this.cols, 1 ); }; Masonry.prototype._getSizingContainer = function() { return this.options.isFitWidth ? this.element.parentNode : this.element; }; Masonry.prototype._getItemLayoutPosition = function( item ) { item.getSize(); // how many columns does this brick span var colSpan = Math.ceil( item.size.outerWidth / this.columnWidth ); colSpan = Math.min( colSpan, this.cols ); var colGroup = this._getColGroup( colSpan ); // get the minimum Y value from the columns var minimumY = Math.min.apply( Math, colGroup ); var shortColIndex = indexOf( colGroup, minimumY ); // position the brick var position = { x: this.columnWidth * shortColIndex, y: minimumY }; // apply setHeight to necessary columns var setHeight = minimumY + item.size.outerHeight; var setSpan = this.cols + 1 - colGroup.length; for ( var i = 0; i < setSpan; i++ ) { this.colYs[ shortColIndex + i ] = setHeight; } return position; }; /** * @param {Number} colSpan - number of columns the element spans * @returns {Array} colGroup */ Masonry.prototype._getColGroup = function( colSpan ) { if ( colSpan === 1 ) { // if brick spans only one column, use all the column Ys return this.colYs; } var colGroup = []; // how many different places could this brick fit horizontally var groupCount = this.cols + 1 - colSpan; // for each group potential horizontal position for ( var i = 0; i < groupCount; i++ ) { // make an array of colY values for that one group var groupColYs = this.colYs.slice( i, i + colSpan ); // and get the max value of the array colGroup[i] = Math.max.apply( Math, groupColYs ); } return colGroup; }; Masonry.prototype._manageStamp = function( stamp ) { var stampSize = getSize( stamp ); var offset = this.isotope._getElementOffset( stamp ); // get the columns that this stamp affects var firstX = this.isotope.options.isOriginLeft ? offset.left : offset.right; var lastX = firstX + stampSize.outerWidth; var firstCol = Math.floor( firstX / this.columnWidth ); firstCol = Math.max( 0, firstCol ); var lastCol = Math.floor( lastX / this.columnWidth ); lastCol = Math.min( this.cols - 1, lastCol ); // set colYs to bottom of the stamp var stampMaxY = ( this.isotope.options.isOriginTop ? offset.top : offset.bottom ) + stampSize.outerHeight; for ( var i = firstCol; i <= lastCol; i++ ) { this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); } }; Masonry.prototype._getContainerSize = function() { this.maxY = Math.max.apply( Math, this.colYs ); var size = { height: this.maxY }; if ( this.options.isFitWidth ) { size.width = this._getContainerFitWidth(); } return size; }; Masonry.prototype._getContainerFitWidth = function() { var unusedCols = 0; // count unused columns var i = this.cols; while ( --i ) { if ( this.colYs[i] !== 0 ) { break; } unusedCols++; } // fit container to columns that have been used return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; }; // debounced, layout on resize // HEADS UP this overwrites Outlayer.resize // Any changes in Outlayer.resize need to be manually added here Masonry.prototype.resize = function() { // don't trigger if size did not change var container = this._getSizingContainer(); var size = getSize( container ); // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var hasSizes = this.size && size; if ( hasSizes && size.innerWidth === this._containerWidth ) { return; } this.layout(); delete this.isotope.resizeTimeout; }; return Masonry; } // -------------------------- transport -------------------------- // if ( typeof define === 'function' && define.amd ) { // AMD define( [ '../isotope', 'get-size/get-size' ], masonryDefinition ); } else { // browser global masonryDefinition( window.Isotope.layoutMode, window.getSize ); } })( window );