123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- /*************************************************
- ** jQuery Masonry version 1.3.2
- ** Copyright David DeSandro, licensed MIT
- ** http://desandro.com/resources/jquery-masonry
- **************************************************/
- ;(function($){
- /*!
- * smartresize: debounced resize event for jQuery
- * http://github.com/lrbabe/jquery-smartresize
- *
- * Copyright (c) 2009 Louis-Remi Babe
- * Licensed under the GPL license.
- * http://docs.jquery.com/License
- *
- */
- var event = $.event,
- resizeTimeout;
- event.special.smartresize = {
- setup: function() {
- $(this).bind( "resize", event.special.smartresize.handler );
- },
- teardown: function() {
- $(this).unbind( "resize", event.special.smartresize.handler );
- },
- handler: function( event, execAsap ) {
- // Save the context
- var context = this,
- args = arguments;
- // set correct event type
- event.type = "smartresize";
- if (resizeTimeout) { clearTimeout(resizeTimeout); }
- resizeTimeout = setTimeout(function() {
- jQuery.event.handle.apply( context, args );
- }, execAsap === "execAsap"? 0 : 100);
- }
- };
- $.fn.smartresize = function( fn ) {
- return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
- };
- // masonry code begin
- $.fn.masonry = function(options, callback) {
- // all my sweet methods
- var msnry = {
- getBricks : function($wall, props, opts) {
- var hasItemSelector = (opts.itemSelector === undefined);
- if ( opts.appendedContent === undefined ) {
- // if not appendedContent
- props.$bricks = hasItemSelector ?
- $wall.children() :
- $wall.find(opts.itemSelector);
- } else {
- // if appendedContent...
- props.$bricks = hasItemSelector ?
- opts.appendedContent :
- opts.appendedContent.filter( opts.itemSelector );
- }
- },
-
- placeBrick : function($brick, setCount, setY, props, opts) {
- // get the minimum Y value from the columns...
- var minimumY = Math.min.apply(Math, setY),
- setHeight = minimumY + $brick.outerHeight(true),
- i = setY.length,
- shortCol = i,
- setSpan = props.colCount + 1 - i;
- // Which column has the minY value, closest to the left
- while (i--) {
- if ( setY[i] == minimumY ) {
- shortCol = i;
- }
- }
-
- var position = {
- left: props.colW * shortCol + props.posLeft,
- top: minimumY
- };
-
- // position the brick
- $brick.applyStyle(position, $.extend(true,{},opts.animationOptions) );
- // apply setHeight to necessary columns
- for ( i=0; i < setSpan; i++ ) {
- props.colY[ shortCol + i ] = setHeight;
- }
- },
-
- setup : function($wall, opts, props) {
- msnry.getBricks($wall, props, opts);
- if ( props.masoned ) {
- props.previousData = $wall.data('masonry');
- }
- if ( opts.columnWidth === undefined) {
- props.colW = props.masoned ?
- props.previousData.colW :
- props.$bricks.outerWidth(true);
- } else {
- props.colW = opts.columnWidth;
- }
- props.colCount = Math.floor( $wall.width() / props.colW ) ;
- props.colCount = Math.max( props.colCount, 1 );
- },
-
- arrange : function($wall, opts, props) {
- var i;
- if ( !props.masoned || opts.appendedContent !== undefined ) {
- // just the new bricks
- props.$bricks.css( 'position', 'absolute' );
- }
- // if masonry hasn't been called before
- if ( !props.masoned ) {
- $wall.css( 'position', 'relative' );
- // get top left position of where the bricks should be
- var $cursor = $( document.createElement('div') );
- $wall.prepend( $cursor );
- props.posTop = Math.round( $cursor.position().top );
- props.posLeft = Math.round( $cursor.position().left );
- $cursor.remove();
- } else {
- props.posTop = props.previousData.posTop;
- props.posLeft = props.previousData.posLeft;
- }
-
- // set up column Y array
- if ( props.masoned && opts.appendedContent !== undefined ) {
- // if appendedContent is set, use colY from last call
- props.colY = props.previousData.colY;
- /*
- * in the case that the wall is not resizeable,
- * but the colCount has changed from the previous time
- * masonry has been called
- */
- for ( i = props.previousData.colCount; i < props.colCount; i++) {
- props.colY[i] = props.posTop;
- }
- } else {
- // start new colY array, with starting values set to posTop
- props.colY = [];
- i = props.colCount;
- while (i--) {
- props.colY.push(props.posTop);
- }
- }
- // are we animating the rearrangement?
- // use plugin-ish syntax for css or animate
- $.fn.applyStyle = ( props.masoned && opts.animate ) ? $.fn.animate : $.fn.css;
- // layout logic
- if ( opts.singleMode ) {
- props.$bricks.each(function(){
- var $brick = $(this);
- msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
- });
- } else {
- props.$bricks.each(function() {
- var $brick = $(this),
- //how many columns does this brick span
- colSpan = Math.ceil( $brick.outerWidth(true) / props.colW);
- colSpan = Math.min( colSpan, props.colCount );
- if ( colSpan === 1 ) {
- // if brick spans only one column, just like singleMode
- msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
- } else {
- // brick spans more than one column
- //how many different places could this brick fit horizontally
- var groupCount = props.colCount + 1 - colSpan,
- groupY = [];
- // for each group potential horizontal position
- for ( i=0; i < groupCount; i++ ) {
- // make an array of colY values for that one group
- var groupColY = props.colY.slice(i, i+colSpan);
- // and get the max value of the array
- groupY[i] = Math.max.apply(Math, groupColY);
- }
- msnry.placeBrick($brick, groupCount, groupY, props, opts);
- }
- }); // /props.bricks.each(function() {
- } // /layout logic
- // set the height of the wall to the tallest column
- props.wallH = Math.max.apply(Math, props.colY);
- var wallCSS = { height: props.wallH - props.posTop };
- $wall.applyStyle( wallCSS, $.extend(true,[],opts.animationOptions) );
- // add masoned class first time around
- if ( !props.masoned ) {
- // wait 1 millisec for quell transitions
- setTimeout(function(){
- $wall.addClass('masoned');
- }, 1);
- }
- // provide props.bricks as context for the callback
- callback.call( props.$bricks );
- // set all data so we can retrieve it for appended appendedContent
- // or anyone else's crazy jquery fun
- $wall.data('masonry', props );
-
- }, // /msnry.arrange
-
- resize : function($wall, opts, props) {
- props.masoned = !!$wall.data('masonry');
- var prevColCount = $wall.data('masonry').colCount;
- msnry.setup($wall, opts, props);
- if ( props.colCount != prevColCount ) {
- msnry.arrange($wall, opts, props);
- }
- }
- };
- /*
- * let's begin
- * IN A WORLD...
- */
- return this.each(function() {
- var $wall = $(this),
- props = {};
- // checks if masonry has been called before on this object
- props.masoned = !!$wall.data('masonry');
-
- var previousOptions = props.masoned ? $wall.data('masonry').options : {},
- opts = $.extend(
- {},
- $.fn.masonry.defaults,
- previousOptions,
- options
- ),
- resizeOn = previousOptions.resizeable;
- // should we save these options for next time?
- props.options = opts.saveOptions ? opts : previousOptions;
- //picked up from Paul Irish
- callback = callback || function(){};
- msnry.getBricks($wall, props, opts);
- // if brickParent is empty, do nothing, go back home and eat chips
- if ( !props.$bricks.length ) {
- return this;
- }
- // call masonry layout
- msnry.setup($wall, opts, props);
- msnry.arrange($wall, opts, props);
-
- // binding window resizing
- if ( !resizeOn && opts.resizeable ) {
- $(window).bind('smartresize.masonry', function() { msnry.resize($wall, opts, props); } );
- }
- if ( resizeOn && !opts.resizeable ) {
- $(window).unbind('smartresize.masonry');
- }
-
- }); // /return this.each(function()
- }; // /$.fn.masonry = function(options)
- // Default plugin options
- $.fn.masonry.defaults = {
- singleMode: false,
- columnWidth: undefined,
- itemSelector: undefined,
- appendedContent: undefined,
- saveOptions: true,
- resizeable: true,
- animate: false,
- animationOptions: {}
- };
- })(jQuery);
|