|
@@ -0,0 +1,205 @@
|
|
|
+/*!
|
|
|
+ * Masonry v4.0.0
|
|
|
+ * Cascading grid layout library
|
|
|
+ * http://masonry.desandro.com
|
|
|
+ * MIT License
|
|
|
+ * by David DeSandro
|
|
|
+ */
|
|
|
+
|
|
|
+( function( window, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */ /*globals define, module, require */
|
|
|
+ if ( typeof define == 'function' && define.amd ) {
|
|
|
+ // AMD
|
|
|
+ define( [
|
|
|
+ 'outlayer/outlayer',
|
|
|
+ 'get-size/get-size'
|
|
|
+ ],
|
|
|
+ factory );
|
|
|
+ } else if ( typeof module == 'object' && module.exports ) {
|
|
|
+ // CommonJS
|
|
|
+ module.exports = factory(
|
|
|
+ require('outlayer'),
|
|
|
+ require('get-size')
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // browser global
|
|
|
+ window.Masonry = factory(
|
|
|
+ window.Outlayer,
|
|
|
+ window.getSize
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}( window, function factory( Outlayer, getSize ) {
|
|
|
+
|
|
|
+'use strict';
|
|
|
+
|
|
|
+// -------------------------- masonryDefinition -------------------------- //
|
|
|
+
|
|
|
+ // create an Outlayer layout class
|
|
|
+ var Masonry = Outlayer.create('masonry');
|
|
|
+ // isFitWidth -> fitWidth
|
|
|
+ Masonry.compatOptions.fitWidth = 'isFitWidth';
|
|
|
+
|
|
|
+ Masonry.prototype._resetLayout = function() {
|
|
|
+ this.getSize();
|
|
|
+ this._getMeasurement( 'columnWidth', 'outerWidth' );
|
|
|
+ this._getMeasurement( 'gutter', 'outerWidth' );
|
|
|
+ this.measureColumns();
|
|
|
+
|
|
|
+ // reset column Y
|
|
|
+ this.colYs = [];
|
|
|
+ for ( var i=0; i < this.cols; i++ ) {
|
|
|
+ this.colYs.push( 0 );
|
|
|
+ }
|
|
|
+
|
|
|
+ this.maxY = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ Masonry.prototype.measureColumns = function() {
|
|
|
+ this.getContainerWidth();
|
|
|
+ // if columnWidth is 0, default to outerWidth of first item
|
|
|
+ if ( !this.columnWidth ) {
|
|
|
+ var firstItem = this.items[0];
|
|
|
+ var firstItemElem = firstItem && firstItem.element;
|
|
|
+ // columnWidth fall back to item of first element
|
|
|
+ this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
|
|
|
+ // if first elem has no width, default to size of container
|
|
|
+ this.containerWidth;
|
|
|
+ }
|
|
|
+
|
|
|
+ var columnWidth = this.columnWidth += this.gutter;
|
|
|
+
|
|
|
+ // calculate columns
|
|
|
+ var containerWidth = this.containerWidth + this.gutter;
|
|
|
+ var cols = containerWidth / columnWidth;
|
|
|
+ // fix rounding errors, typically with gutters
|
|
|
+ var excess = columnWidth - containerWidth % columnWidth;
|
|
|
+ // if overshoot is less than a pixel, round up, otherwise floor it
|
|
|
+ var mathMethod = excess && excess < 1 ? 'round' : 'floor';
|
|
|
+ cols = Math[ mathMethod ]( cols );
|
|
|
+ this.cols = Math.max( cols, 1 );
|
|
|
+ };
|
|
|
+
|
|
|
+ Masonry.prototype.getContainerWidth = function() {
|
|
|
+ // container is parent if fit width
|
|
|
+ var isFitWidth = this._getOption('fitWidth');
|
|
|
+ var container = isFitWidth ? this.element.parentNode : this.element;
|
|
|
+ // check that this.size and size are there
|
|
|
+ // IE8 triggers resize on body size change, so they might not be
|
|
|
+ var size = getSize( container );
|
|
|
+ this.containerWidth = size && size.innerWidth;
|
|
|
+ };
|
|
|
+
|
|
|
+ Masonry.prototype._getItemLayoutPosition = function( item ) {
|
|
|
+ item.getSize();
|
|
|
+ // how many columns does this brick span
|
|
|
+ var remainder = item.size.outerWidth % this.columnWidth;
|
|
|
+ var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
|
|
|
+ // round if off by 1 pixel, otherwise use ceil
|
|
|
+ var colSpan = Math[ mathMethod ]( 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 = colGroup.indexOf( 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 < 2 ) {
|
|
|
+ // 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._getElementOffset( stamp );
|
|
|
+ // get the columns that this stamp affects
|
|
|
+ var isOriginLeft = this._getOption('originLeft');
|
|
|
+ var firstX = 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 should not go over if multiple of columnWidth #425
|
|
|
+ lastCol -= lastX % this.columnWidth ? 0 : 1;
|
|
|
+ lastCol = Math.min( this.cols - 1, lastCol );
|
|
|
+ // set colYs to bottom of the stamp
|
|
|
+
|
|
|
+ var isOriginTop = this._getOption('originTop');
|
|
|
+ var stampMaxY = ( 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._getOption('fitWidth') ) {
|
|
|
+ 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;
|
|
|
+ };
|
|
|
+
|
|
|
+ Masonry.prototype.needsResizeLayout = function() {
|
|
|
+ var previousWidth = this.containerWidth;
|
|
|
+ this.getContainerWidth();
|
|
|
+ return previousWidth != this.containerWidth;
|
|
|
+ };
|
|
|
+
|
|
|
+ return Masonry;
|
|
|
+
|
|
|
+}));
|