Вход Регистрация
Файл: CloudBox-main/CloudBox/admin_assets/js/gallery/shuffle.js
Строк: 1516
<?php
/*!
 * Shuffle.js by @Vestride
 * Categorize, sort, and filter a responsive grid of items.
 * Dependencies: jQuery 1.9+, Modernizr 2.6.2+
 * @license MIT license
 * @version 2.1.1
 */
(function (factory) {
    if (
typeof define === 'function' && define.amd) {
        
define(['jquery''modernizr'], factory);
    } else {
        
factory(window.$, window.Modernizr);
    }
})(function($, 
Modernizrundefined) {

    
'use strict';


// Validate Modernizr exists.
// Shuffle requires `csstransitions`, `csstransforms`, `csstransforms3d`,
// and `prefixed` to exist on the Modernizr object.
    
if (typeof Modernizr !== 'object') {
        throw new 
Error('Shuffle.js requires Modernizr.n' +
            
'http://vestride.github.io/Shuffle/#dependencies');
    }


    
/**
     * Returns css prefixed properties like `-webkit-transition` or `box-sizing`
     * from `transition` or `boxSizing`, respectively.
     * @param {(string|boolean)} prop Property to be prefixed.
     * @return {string} The prefixed css property.
     */
    
function dashifyprop ) {
        if (!
prop) {
            return 
'';
        }

        
// Replace upper case with dash-lowercase,
        // then fix ms- prefixes because they're not capitalized.
        
return prop.replace(/([A-Z])/g, function( strm1 ) {
            return 
'-' m1.toLowerCase();
        }).
replace(/^ms-/,'-ms-');
    }

// Constant, prefixed variables.
    
var TRANSITION Modernizr.prefixed('transition');
    var 
TRANSITION_DELAY Modernizr.prefixed('transitionDelay');
    var 
TRANSITION_DURATION Modernizr.prefixed('transitionDuration');
    var 
TRANSITIONEND = {
        
'WebkitTransition' 'webkitTransitionEnd',
        
'transition' 'transitionend'
    
}[ TRANSITION ];
    var 
TRANSFORM Modernizr.prefixed('transform');
    var 
CSS_TRANSFORM dashify(TRANSFORM);

// Constants
    
var CAN_TRANSITION_TRANSFORMS Modernizr.csstransforms && Modernizr.csstransitions;
    var 
HAS_TRANSFORMS_3D Modernizr.csstransforms3d;
    var 
SHUFFLE 'shuffle';

// Configurable. You can change these constants to fit your application.
// The default scale and concealed scale, however, have to be different values.
    
var ALL_ITEMS 'all';
    var 
FILTER_ATTRIBUTE_KEY 'groups';
    var 
DEFAULT_SCALE 1;
    var 
CONCEALED_SCALE 0.001;


// Underscore's throttle function.
    
function throttle(funcwaitoptions) {
        var 
contextargsresult;
        var 
timeout null;
        var 
previous 0;
        
options options || {};
        var 
later = function() {
            
previous options.leading === false : $.now();
            
timeout null;
            
result func.apply(contextargs);
            
context args null;
        };
        return function() {
            var 
now = $.now();
            if (!
previous && options.leading === false) {
                
previous now;
            }
            var 
remaining wait - (now previous);
            
context this;
            
args arguments;
            if (
remaining <= || remaining wait) {
                
clearTimeout(timeout);
                
timeout null;
                
previous now;
                
result func.apply(contextargs);
                
context args null;
            } else if (!
timeout && options.trailing !== false) {
                
timeout setTimeout(laterremaining);
            }
            return 
result;
        };
    }

// Used for unique instance variables
    
var id 0;


    
/**
     * Categorize, sort, and filter a responsive grid of items.
     *
     * @param {Element|jQuery} element An element or a jQuery collection which
     *     is the parent container for the grid items.
     * @param {Object} [options=Shuffle.options] Options object.
     * @constructor
     */
    
var Shuffle = function( elementoptions ) {
        
options options || {};
        $.
extendthisShuffle.optionsoptionsShuffle.settings );

        
this.$el = $(element);
        
this.$window = $(window);
        
this.unique 'shuffle_' id++;

        
this._fireShuffle.EventType.LOADING );
        
this._init();

        
// Dispatch the done event asynchronously so that people can bind to it after
        // Shuffle has been initialized.
        
setTimeout( $.proxy(function() {
            
this.initialized true;
            
this._fireShuffle.EventType.DONE );
        }, 
this), 16 );
    };


    
/**
     * Events the container element emits with the .shuffle namespace.
     * For example, "done.shuffle".
     * @enum {string}
     */
    
Shuffle.EventType = {
        
LOADING'loading',
        
DONE'done',
        
SHRINK'shrink',
        
SHRUNK'shrunk',
        
FILTER'filter',
        
FILTERED'filtered',
        
SORTED'sorted',
        
LAYOUT'layout',
        
REMOVED'removed'
    
};


    
Shuffle.prototype = {

        
_init : function() {
            var 
self this,
                
containerCSS,
                
containerWidth,
                
resizeFunction = $.proxyself._onResizeself ),
                
debouncedResize self.throttle ?
                    
self.throttleresizeFunctionself.throttleTime ) :
                    
resizeFunction,
                
sort self.initialSort self.initialSort null;


            
self._layoutList = [];
            
self._shrinkList = [];

            
self._setVars();

            
// Zero out all columns
            
self._resetCols();

            
// Add classes and invalidate styles
            
self._addClasses();

            
// Set initial css for each item
            
self._initItems();

            
// Bind resize events
            // http://stackoverflow.com/questions/1852751/window-resize-event-firing-in-internet-explorer
            
self.$window.on('resize.' SHUFFLE '.' self.uniquedebouncedResize);

            
// Get container css all in one request. Causes reflow
            
containerCSS self.$el.css(['paddingLeft''paddingRight''position']);
            
containerWidth self._getOuterWidthself.$el[0] );

            
// Position cannot be static.
            
if ( containerCSS.position === 'static' ) {
                
self.$el[0].style.position 'relative';
            }

            
// Get offset from container
            
self.offset = {
                
leftparseIntcontainerCSS.paddingLeft10 ) || 0,
                
topparseIntcontainerCSS.paddingTop10 ) || 0
            
};

            
// We already got the container's width above, no need to cause another reflow getting it again...
            // Calculate the number of columns there will be
            
self._setColumnsparseIntcontainerWidth10 ) );

            
// Kick off!
            
self.shuffleself.groupsort );

            
// The shuffle items haven't had transitions set on them yet
            // so the user doesn't see the first layout. Set them now that the first layout is done.
            
if ( self.supported ) {
                
setTimeout(function() {
                    
self._setTransitions();
                    
self.$el[0].styleTRANSITION ] = 'height ' self.speed 'ms ' self.easing;
                }, 
0);
            }
        },

        
// Will invalidate styles
        
_addClasses : function() {
            
this.$el.addClassSHUFFLE );
            
this.$items.addClass('shuffle-item filtered');
        },

        
_setVars : function() {
            var 
self this,
                
columnWidth self.columnWidth;

            
self.$items self._getItems();

            
// Column width is the default setting and sizer is not (meaning passed in)
            // Assume they meant column width to be the sizer
            
if ( columnWidth === && self.sizer !== null ) {
                
columnWidth self.sizer;
            }

            
// If column width is a string, treat is as a selector and search for the
            // sizer element within the outermost container
            
if ( typeof columnWidth === 'string' ) {
                
self.$sizer self.$el.findcolumnWidth );

                
// Check for an element
            
} else if ( columnWidth && columnWidth.nodeType && columnWidth.nodeType === ) {
                
// Wrap it in jQuery
                
self.$sizer = $( columnWidth );

                
// Check for jQuery object
            
} else if ( columnWidth && columnWidth.jquery ) {
                
self.$sizer columnWidth;
            }

            if ( 
self.$sizer && self.$sizer.length ) {
                
self.useSizer true;
                
self.sizer self.$sizer[0];
            }
        },


        
/**
         * Filter the elements by a category.
         * @param {string} [category] Category to filter by. If it's given, the last
         *     category will be used to filter the items.
         * @param {jQuery} [$collection] Optionally filter a collection. Defaults to
         *     all the items.
         * @return {jQuery} Filtered items.
         */
        
_filter : function( category$collection ) {
            var 
self this,
                
isPartialSet $collection !== undefined,
                
$items isPartialSet $collection self.$items,
                
$filtered = $();

            
category category || self.lastFilter;

            
self._fireShuffle.EventType.FILTER );

            
// Loop through each item and use provided function to determine
            // whether to hide it or not.
            
if ( $.isFunctioncategory ) ) {
                
$items.each(function() {
                    var 
$item = $(this);
                    if ( 
category.call($item[0], $itemself) ) {
                        
$filtered $filtered.add$item );
                    }
                });

                
// Otherwise we've been passed a category to filter by
            
} else {
                
self.group category;

                
// category === 'all', add filtered class to everything
                
if ( category === ALL_ITEMS ) {
                    
$filtered $items;

                    
// Check each element's data-groups attribute against the given category.
                
} else {
                    
$items.each(function() {
                        var 
$item = $(this),
                            
groups $item.dataFILTER_ATTRIBUTE_KEY ),
                            
keys self.delimeter && !$.isArraygroups ) ?
                                
groups.splitself.delimeter ) :
                                
groups;

                        if ( $.
inArray(categorykeys) > -) {
                            
$filtered $filtered.add$item );
                        }
                    });
                }
            }

            
// Individually add/remove concealed/filtered classes
            
self._toggleFilterClasses$items$filtered );

            
$items null;
            
$collection null;

            return 
$filtered;
        },


        
_toggleFilterClasses : function( $items$filtered ) {
            var 
concealed 'concealed',
                
filtered 'filtered';

            
$items.filter$filtered ).each(function() {
                var 
$filteredItem = $(this);
                
// Remove concealed if it's there
                
if ( $filteredItem.hasClassconcealed ) ) {
                    
$filteredItem.removeClassconcealed );
                }
                
// Add filtered class if it's not there
                
if ( !$filteredItem.hasClassfiltered ) ) {
                    
$filteredItem.addClassfiltered );
                }
            });

            
$items.not$filtered ).each(function() {
                var 
$filteredItem = $(this);
                
// Add concealed if it's not there
                
if ( !$filteredItem.hasClassconcealed ) ) {
                    
$filteredItem.addClassconcealed );
                }
                
// Remove filtered class if it's there
                
if ( $filteredItem.hasClassfiltered ) ) {
                    
$filteredItem.removeClassfiltered );
                }
            });
        },

        
/**
         * Set the initial css for each item
         * @param {jQuery} [$items] Optionally specifiy at set to initialize
         */
        
_initItems : function( $items ) {
            
$items $items || this.$items;
            
$items.cssthis.itemCss ).data('position', {x0y0});
        },

        
_updateItemCount : function() {
            
this.visibleItems this.$items.filter('.filtered').length;
        },

        
_setTransition : function( element ) {
            
element.styleTRANSITION ] = CSS_TRANSFORM ' ' this.speed 'ms ' this.easing ', opacity ' this.speed 'ms ' this.easing;
        },

        
_setTransitions : function( $items ) {
            var 
self this;

            
$items $items || self.$items;
            
$items.each(function() {
                
self._setTransitionthis );
            });
        },

        
_setSequentialDelay : function( $collection ) {
            var 
self this;

            if ( !
self.supported ) {
                return;
            }

            
// $collection can be an array of dom elements or jquery object
            
$.each($collection, function(iel) {
                
// This works because the transition-property: transform, opacity;
                
el.styleTRANSITION_DELAY ] = '0ms,' + ((1) * self.sequentialFadeDelay) + 'ms';

                
// Set the delay back to zero after one transition
                
$(el).on(TRANSITIONEND '.' self.unique, function(evt) {
                    var 
target evt.currentTarget;
                    if ( 
target === evt.target ) {
                        
target.styleTRANSITION_DELAY ] = '0ms';
                        $(
target).off(TRANSITIONEND '.' self.unique);
                    }
                });
            });
        },

        
_getItems : function() {
            return 
this.$el.childrenthis.itemSelector );
        },

        
_getPreciseDimension : function( elementstyle ) {
            var 
dimension;
            if ( 
window.getComputedStyle ) {
                
dimension window.getComputedStyleelementnull )[ style ];
            } else {
                
dimension = $( element ).cssstyle );
            }
            return 
parseFloatdimension );
        },


        
/**
         * Returns the outer width of an element, optionally including its margins.
         * @param {Element} element The element.
         * @param {boolean} [includeMargins] Whether to include margins. Default is false.
         * @return {number} The width.
         */
        
_getOuterWidth : function( elementincludeMargins ) {
            var 
width element.offsetWidth;

            
// Use jQuery here because it uses getComputedStyle internally and is
            // cross-browser. Using the style property of the element will only work
            // if there are inline styles.
            
if (includeMargins) {
                var 
styles = $(element).css(['marginLeft''marginRight']);

                
// Defaults to zero if parsing fails because IE will return 'auto' when
                // the element doesn't have margins instead of the computed style.
                
var marginLeft parseFloat(styles.marginLeft) || 0;
                var 
marginRight parseFloat(styles.marginRight) || 0;
                
width += marginLeft marginRight;
            }

            return 
width;
        },


        
/**
         * Returns the outer height of an element, optionally including its margins.
         * @param {Element} element The element.
         * @param {boolean} [includeMargins] Whether to include margins. Default is false.
         * @return {number} The height.
         */
        
_getOuterHeight : function( elementincludeMargins ) {
            var 
height element.offsetHeight;

            if (
includeMargins) {
                var 
styles = $(element).css(['marginTop''marginBottom']);
                var 
marginTop parseFloat(styles.marginTop) || 0;
                var 
marginBottom parseFloat(styles.marginBottom) || 0;
                
height += marginTop marginBottom;
            }

            return 
height;
        },


        
_getColumnSize : function( gutterSizecontainerWidth ) {
            var 
size;

            
// If the columnWidth property is a function, then the grid is fluid
            
if ( $.isFunctionthis.columnWidth ) ) {
                
size this.columnWidth(containerWidth);

                
// columnWidth option isn't a function, are they using a sizing element?
            
} else if ( this.useSizer ) {
                
size this._getPreciseDimension(this.sizer'width');

                
// if not, how about the explicitly set option?
            
} else if ( this.columnWidth ) {
                
size this.columnWidth;

                
// or use the size of the first item
            
} else if ( this.$items.length ) {
                
size this._getOuterWidth(this.$items[0], true);

                
// if there's no items, use size of container
            
} else {
                
size containerWidth;
            }

            
// Don't let them set a column width of zero.
            
if ( size === ) {
                
size containerWidth;
            }

            return 
size gutterSize;
        },


        
_getGutterSize : function( containerWidth ) {
            var 
size;
            if ( $.
isFunctionthis.gutterWidth ) ) {
                
size this.gutterWidth(containerWidth);
            } else if ( 
this.useSizer ) {
                
size this._getPreciseDimension(this.sizer'marginLeft');
            } else {
                
size this.gutterWidth;
            }

            return 
size;
        },


        
/**
         * Calculate the number of columns to be used. Gets css if using sizer element.
         * @param {number} [theContainerWidth] Optionally specify a container width if it's already available.
         */
        
_setColumns : function( theContainerWidth ) {
            var 
containerWidth theContainerWidth || this._getOuterWidth(this.$el[0]);
            var 
gutter this._getGutterSize(containerWidth);
            var 
columnWidth this._getColumnSize(guttercontainerWidth);
            var 
calculatedColumns = (containerWidth gutter) / columnWidth;

            
// Widths given from getComputedStyle are not precise enough...
            
if ( Math.abs(Math.round(calculatedColumns) - calculatedColumns) < 0.03 ) {
                
// e.g. calculatedColumns = 11.998876
                
calculatedColumns Math.roundcalculatedColumns );
            }

            
this.cols Math.maxMath.floor(calculatedColumns), );
            
this.containerWidth containerWidth;
            
this.colWidth columnWidth;
        },

        
/**
         * Adjust the height of the grid
         */
        
_setContainerSize : function() {
            var 
customData Math.max.applyMaththis.colYs)+5;
            
this.$el.css'height'customData);
        },

        
/**
         * Fire events with .shuffle namespace
         */
        
_fire : function( nameargs ) {
            
this.$el.triggername '.' SHUFFLEargs && args.length args : [ this ] );
        },


        
/**
         * Loops through each item that should be shown and calculates the x, y position.
         * @param {Array.<Element>} items Array of items that will be shown/layed out in order in their array.
         *     Because jQuery collection are always ordered in DOM order, we can't pass a jq collection.
         * @param {function} fn Callback function.
         * @param {boolean} isOnlyPosition If true this will position the items with zero opacity.
         */
        
_layout : function( itemsfnisOnlyPosition ) {
            var 
self this;

            
fn fn || self._filterEnd;

            $.
each(items, function(indexitem) {
                var 
$item = $(item);
                var 
itemData $item.data();
                var 
currPos itemData.position;
                var 
pos self._getItemPosition$item );

                
// Save data for shrink
                
$item.data'position'pos );

                
// If the item will not change its position, do not add it to the render
                // queue. Transitions don't fire when setting a property to the same value.
                
if ( pos.=== currPos.&& pos.=== currPos.&& itemData.scale === DEFAULT_SCALE ) {
                    return;
                }

                var 
transitionObj = {
                    
$item$item,
                    
xpos.x,
                    
ypos.y,
                    
scaleDEFAULT_SCALE
                
};

                if ( 
isOnlyPosition ) {
                    
transitionObj.skipTransition true;
                    
transitionObj.opacity 0;
                } else {
                    
transitionObj.opacity 1;
                    
transitionObj.callback fn;
                }

                
self.styleQueue.pushtransitionObj );
                
self._layoutList.push$item[0] );
            });

            
// `_layout` always happens after `_shrink`, so it's safe to process the style
            // queue here with styles from the shrink method
            
self._processStyleQueue();

            
// Adjust the height of the container
            
self._setContainerSize();
        },

        
// Reset columns.
        
_resetCols : function() {
            var 
this.cols;
            
this.colYs = [];
            while (
i--) {
                
this.colYs.push);
            }
        },

        
_reLayout : function() {
            
this._resetCols();

            
// If we've already sorted the elements, keep them sorted
            
if ( this.lastSort ) {
                
this.sortthis.lastSorttrue );
            } else {
                
this._layoutthis.$items.filter('.filtered').get(), this._filterEnd );
            }
        },

        
_getItemPosition : function( $item ) {
            var 
self this;
            var 
itemWidth self._getOuterWidth$item[0], true );
            var 
columnSpan itemWidth self.colWidth;

            
// If the difference between the rounded column span number and the
            // calculated column span number is really small, round the number to
            // make it fit.
            
if ( Math.abs(Math.round(columnSpan) - columnSpan) < 0.03 ) {
                
// e.g. columnSpan = 4.0089945390298745
                
columnSpan Math.roundcolumnSpan );
            }

            
// How many columns does this item span. Ensure it's not more than the
            // amount of columns in the whole layout.
            
var colSpan Math.minMath.ceil(columnSpan), self.cols );

            
// The item spans only one column.
            
if ( colSpan === ) {
                return 
self._placeItem$itemself.colYs );

                
// The item spans more than one column, figure out how many different
                // places it could fit horizontally
            
} else {
                var 
groupCount self.cols colSpan,
                    
groupY = [],
                    
groupColY,
                    
i;

                
// for each group potential horizontal position
                
for ( 0groupCounti++ ) {
                    
// make an array of colY values for that one group
                    
groupColY self.colYs.sliceicolSpan );
                    
// and get the max value of the array
                    
groupY[i] = Math.max.applyMathgroupColY );
                }

                return 
self._placeItem$itemgroupY );
            }
        },

        
// worker method that places item in the columnSet with the the minY
        
_placeItem : function( $itemsetY ) {
            
// get the minimum Y value from the columns
            
var self this,
                
minimumY Math.min.applyMathsetY ),
                
shortCol 0;

            
// Find index of short column, the first from the left where this item will go
            // if ( setY[i] === minimumY ) requires items' height to be exact every time.
            // The buffer value is very useful when the height is a percentage of the width
            
for (var 0len setY.lengthleni++) {
                if ( 
setY[i] >= minimumY self.buffer && setY[i] <= minimumY self.buffer ) {
                    
shortCol i;
                    break;
                }
            }

            
// Position the item
            
var position = {
                
xMath.round( (self.colWidth shortCol) + self.offset.left ),
                
yMath.roundminimumY self.offset.top )
            };

            
// Apply setHeight to necessary columns
            
var setHeight minimumY self._getOuterHeight$item[0], true ),
                
setSpan self.cols len;
            for ( 
0setSpani++ ) {
                
self.colYsshortCol ] = setHeight;
            }

            return 
position;
        },

        
/**
         * Hides the elements that don't match our filter.
         * @param {jQuery} $collection jQuery collection to shrink.
         * @param {Function} fn Callback function.
         * @private
         */
        
_shrink : function( $collectionfn ) {
            var 
self this,
                
$concealed $collection || self.$items.filter('.concealed');

            
fn fn || self._shrinkEnd;

            
// Abort if no items
            
if ( !$concealed.length ) {
                return;
            }

            
self._fireShuffle.EventType.SHRINK );

            
$concealed.each(function() {
                var 
$item = $(this);
                var 
itemData $item.data();
                var 
alreadyShrunk itemData.scale === CONCEALED_SCALE;

                
// Continuing would add a transitionend event listener to the element, but
                // that listener would execute because the transform and opacity would
                // stay the same.
                
if ( alreadyShrunk ) {
                    return;
                }

                var 
transitionObj = {
                    
$item$item,
                    
xitemData.position.x,
                    
yitemData.position.y,
                    
scale CONCEALED_SCALE,
                    
opacity0,
                    
callbackfn
                
};

                
self.styleQueue.pushtransitionObj );
                
self._shrinkList.push$item[0] );
            });
        },

        
_onResize : function() {
            
// If shuffle is disabled, destroyed, don't do anything
            
if ( !this.enabled || this.destroyed ) {
                return;
            }

            
// Will need to check height in the future if it's layed out horizontaly
            
var containerWidth this._getOuterWidth(this.$el[0]);

            
// containerWidth hasn't changed, don't do anything
            
if ( containerWidth === this.containerWidth ) {
                return;
            }

            
this.resized();
        },


        
/**
         * If the browser has 3d transforms available, build a string with those,
         * otherwise use 2d transforms.
         * @param {number} x X position.
         * @param {number} y Y position.
         * @param {number} scale Scale amount.
         * @return {string} A normalized string which can be used with the transform style.
         * @private
         */
        
_getItemTransformString : function(xyscale) {
            if ( 
HAS_TRANSFORMS_3D ) {
                return 
'translate3d(' 'px, ' 'px, 0) scale3d(' scale ', ' scale ', 1)';
            } else {
                return 
'translate(' 'px, ' 'px) scale(' scale ', ' scale ')';
            }
        },

        
_getStylesForTransition : function( opts ) {
            var 
styles = {
                
opacityopts.opacity
            
};

            if ( 
this.supported ) {
                if ( 
opts.!== undefined ) {
                    
stylesTRANSFORM ] = this._getItemTransformStringopts.xopts.yopts.scale );
                }
            } else {
                
styles.left opts.x;
                
styles.top opts.y;
            }


            
// Show the item if its opacity will be 1.
            
if ( opts.opacity === ) {
                
styles.visibility 'visible';
            }

            return 
styles;
        },

        
/**
         * Transitions an item in the grid
         *
         * @param {Object}   opts options
         * @param {jQuery}   opts.$item jQuery object representing the current item
         * @param {number}   opts.x translate's x
         * @param {number}   opts.y translate's y
         * @param {number}   opts.scale amount to scale the item
         * @param {number}   opts.opacity opacity of the item
         * @param {Function} opts.callback complete function for the animation
         * @private
         */
        
_transition : function( opts ) {
            
opts.$item.data('scale'opts.scale);

            var 
styles this._getStylesForTransitionopts );
            
this._startItemAnimationopts.$itemstylesopts.callback );
        },


        
_startItemAnimation : function( $itemstylescallback ) {
            var 
willBeVisible styles.opacity === 1;
            var 
complete = $.proxythis._handleItemAnimationEndthis,
                
callback || $.noop$item[0], willBeVisible );

            
// Use CSS Transforms if we have them
            
if ( this.supported ) {

                
$item.cssstyles );

                
// Transitions are not set until shuffle has loaded to avoid the initial transition.
                
if ( this.initialized ) {
                    
// Namespaced because the reveal appended function also wants to know
                    // about the transition end event.
                    
$item.onTRANSITIONEND '.shuffleitem'complete );
                } else {
                    
complete();
                }

                
// Use jQuery to animate left/top
            
} else {
                
// jQuery cannot animate visibility, set it immediately.
                
if ( 'visibility' in styles ) {
                    
$item.css('visibility'styles.visibility);
                    
delete styles.visibility;
                }
                
$item.stoptrue ).animatestylesthis.speed'swing'complete );
            }
        },


        
_handleItemAnimationEnd : function( callbackitemwillBeVisibleevt ) {
            
// Make sure this event handler has not bubbled up from a child.
            
if ( evt ) {
                if ( 
evt.target === item ) {
                    $( 
item ).off'.shuffleitem' );
                } else {
                    return;
                }
            }

            if ( 
this._layoutList.length && $.inArrayitemthis._layoutList ) > -) {
                
this._fireShuffle.EventType.LAYOUT );
                
callback.callthis );
                
this._layoutList.length 0;
            } else if ( 
this._shrinkList.length && $.inArrayitemthis._shrinkList ) > -) {
                
callback.callthis );
                
this._shrinkList.length 0;
            }

            if ( !
willBeVisible ) {
                
item.style.visibility 'hidden';
            }
        },

        
_processStyleQueue : function() {
            var 
self this;

            $.
each(this.styleQueue, function(itransitionObj) {

                if ( 
transitionObj.skipTransition ) {
                    
self._skipTransition(transitionObj.$item[0], function() {
                        
transitionObj.$item.cssself._getStylesForTransitiontransitionObj ) );
                    });
                } else {
                    
self._transitiontransitionObj );
                }
            });

            
// Remove everything in the style queue
            
self.styleQueue.length 0;
        },

        
_shrinkEnd : function() {
            
this._fireShuffle.EventType.SHRUNK );
        },

        
_filterEnd : function() {
            
this._fireShuffle.EventType.FILTERED );
        },

        
_sortEnd : function() {
            
this._fireShuffle.EventType.SORTED );
        },

        
/**
         * Change a property or execute a function which will not have a transition
         * @param {Element} element DOM element that won't be transitioned
         * @param {(string|Function)} property The new style property which will be set or a function which will be called
         * @param {string} [value] The value that `property` should be.
         * @private
         */
        
_skipTransition : function( elementpropertyvalue ) {
            var 
duration element.styleTRANSITION_DURATION ];

            
// Set the duration to zero so it happens immediately
            
element.styleTRANSITION_DURATION ] = '0ms'// ms needed for firefox!

            
if ( $.isFunctionproperty ) ) {
                
property();
            } else {
                
element.styleproperty ] = value;
            }

            
// Force reflow
            
var reflow element.offsetWidth;
            
// Avoid jshint warnings: unused variables and expressions.
            
reflow null;

            
// Put the duration back
            
element.styleTRANSITION_DURATION ] = duration;
        },

        
_addItems : function( $newItemsanimateInisSequential ) {
            var 
self this;

            if ( !
self.supported ) {
                
animateIn false;
            }

            
$newItems.addClass('shuffle-item');
            
self._initItems$newItems );
            
self._setTransitions$newItems );
            
self.$items self._getItems();

            
// Hide all items
            
$newItems.css('opacity'0);

            
// Get ones that passed the current filter
            
var $passed self._filterundefined$newItems );
            var 
passed $passed.get();

            
// How many filtered elements?
            
self._updateItemCount();

            if ( 
animateIn ) {
                
self._layoutpassednulltrue );

                if ( 
isSequential ) {
                    
self._setSequentialDelay$passed );
                }

                
self._revealAppended$passed );
            } else {
                
self._layoutpassed );
            }
        },

        
_revealAppended : function( $newFilteredItems ) {
            var 
self this;

            
setTimeout(function() {
                
$newFilteredItems.each(function(iel) {
                    
self._transition({
                        
$item: $(el),
                        
opacity1,
                        
scaleDEFAULT_SCALE
                    
});
                });
            }, 
self.revealAppendedDelay);
        },


        
/**
         * Public Methods
         */

        /**
         * The magic. This is what makes the plugin 'shuffle'
         * @param {(string|Function)} [category] Category to filter by. Can be a function
         * @param {Object} [sortObj] A sort object which can sort the filtered set
         */
        
shuffle : function( categorysortObj ) {
            var 
self this;

            if ( !
self.enabled ) {
                return;
            }

            if ( !
category ) {
                
category ALL_ITEMS;
            }

            
self._filtercategory );
            
// Save the last filter in case elements are appended.
            
self.lastFilter category;

            
// How many filtered elements?
            
self._updateItemCount();

            
// Shrink each concealed item
            
self._shrink();

            
// If given a valid sort object, save it so that _reLayout() will sort the items
            
if ( sortObj ) {
                
self.lastSort sortObj;
            }
            
// Update transforms on .filtered elements so they will animate to their new positions
            
self._reLayout();
        },

        
/**
         * Gets the .filtered elements, sorts them, and passes them to layout
         *
         * @param {Object} opts the options object for the sorted plugin
         * @param {boolean} [fromFilter] was called from Shuffle.filter method.
         */
        
sort : function( optsfromFilter ) {
            var 
self this,
                
items self.$items.filter('.filtered').sorted(opts);

            if ( !
fromFilter ) {
                
self._resetCols();
            }

            
self._layout(items, function() {
                if (
fromFilter) {
                    
self._filterEnd();
                }
                
self._sortEnd();
            });

            
self.lastSort opts;
        },

        
/**
         * Relayout everything
         */
        
resized : function( isOnlyLayout ) {
            if ( 
this.enabled ) {

                if ( !
isOnlyLayout ) {
                    
// Get updated colCount
                    
this._setColumns();
                }

                
// Layout items
                
this._reLayout();
            }
        },

        
/**
         * Use this instead of `update()` if you don't need the columns and gutters updated
         * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations
         * could be off.
         */
        
layout : function() {
            
this.updatetrue );
        },

        
update : function( isOnlyLayout ) {
            
this.resizedisOnlyLayout );
        },

        
/**
         * New items have been appended to shuffle. Fade them in sequentially
         * @param {jQuery} $newItems jQuery collection of new items
         * @param {boolean} [animateIn] If false, the new items won't animate in
         * @param {boolean} [isSequential] If false, new items won't sequentially fade in
         */
        
appended : function( $newItemsanimateInisSequential ) {
            
// True if undefined
            
animateIn animateIn === false false true;
            
isSequential isSequential === false false true;

            
this._addItems$newItemsanimateInisSequential );
        },

        
/**
         * Disables shuffle from updating dimensions and layout on resize
         */
        
disable : function() {
            
this.enabled false;
        },

        
/**
         * Enables shuffle again
         * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters
         */
        
enable : function( isUpdateLayout ) {
            
this.enabled true;
            if ( 
isUpdateLayout !== false ) {
                
this.update();
            }
        },

        
/**
         * Remove 1 or more shuffle items
         * @param {jQuery} $collection A jQuery object containing one or more element in shuffle
         * @return {Shuffle} The shuffle object
         */
        
remove : function( $collection ) {

            
// If this isn't a jquery object, exit
            
if ( !$collection.length || !$collection.jquery ) {
                return;
            }

            var 
self this;

            
// Hide collection first
            
self._shrink$collection, function() {
                var 
shuffle this;

                
// Remove the collection in the callback
                
$collection.remove();

                
// Update the items, layout, count and fire off `removed` event
                
setTimeout(function() {
                    
shuffle.$items shuffle._getItems();
                    
shuffle.layout();
                    
shuffle._updateItemCount();
                    
shuffle._fireShuffle.EventType.REMOVED, [ $collectionshuffle ] );

                    
// Let it get garbage collected
                    
$collection null;
                }, 
0);
            });

            
// Process changes
            
self._processStyleQueue();

            return 
self;
        },

        
/**
         * Destroys shuffle, removes events, styles, and classes
         */
        
destroy : function() {
            var 
self this;

            
// If there is more than one shuffle instance on the page,
            // removing the resize handler from the window would remove them
            // all. This is why a unique value is needed.
            
self.$window.off('.' self.unique);

            
// Reset container styles
            
self.$el
                
.removeClassSHUFFLE )
                .
removeAttr('style')
                .
removeDataSHUFFLE );

            
// Reset individual item styles
            
self.$items
                
.removeAttr('style')
                .
removeClass('concealed filtered shuffle-item');

            
// Null DOM references
            
self.$window null;
            
self.$items null;
            
self.$el null;
            
self.$sizer null;
            
self.sizer null;

            
// Set a flag so if a debounced resize has been triggered,
            // it can first check if it is actually destroyed and not doing anything
            
self.destroyed true;
        }
    };


// Overrideable options
    
Shuffle.options = {
        
groupALL_ITEMS// Filter group
        
speed250// Transition/animation speed (milliseconds)
        
easing'ease-out'// css easing function to use
        
itemSelector''// e.g. '.picture-item'
        
sizernull// sizer element. Can be anything columnWidth is
        
gutterWidth0// a static number or function that tells the plugin how wide the gutters between columns are (in pixels)
        
columnWidth0// a static number or function that returns a number which tells the plugin how wide the columns are (in pixels)
        
delimeternull// if your group is not json, and is comma delimeted, you could set delimeter to ','
        
buffer0// useful for percentage based heights when they might not always be exactly the same (in pixels)
        
initialSortnull// Shuffle can be initialized with a sort object. It is the same object given to the sort method
        
throttlethrottle// By default, shuffle will try to throttle the resize event. This option will change the method it uses
        
throttleTime300// How often shuffle can be called on resize (in milliseconds)
        
sequentialFadeDelay150// Delay between each item that fades in when adding items
        
supportedCAN_TRANSITION_TRANSFORMS // supports transitions and transforms
    
};


// Not overrideable
    
Shuffle.settings = {
        
$sizernull,
        
useSizerfalse,
        
itemCss : { // default CSS for each item
            
position'absolute',
            
top0,
            
left0
        
},
        
offset: { top0left},
        
revealAppendedDelay300,
        
enabledtrue,
        
destroyedfalse,
        
initializedfalse,
        
styleQueue: []
    };


// Plugin definition
    
$.fn.shuffle = function( opts ) {
        var 
args = Array.prototype.slice.callarguments);
        return 
this.each(function() {
            var 
$this = $( this ),
                
shuffle $this.dataSHUFFLE );

            
// If we don't have a stored shuffle, make a new one and save it
            
if ( !shuffle ) {
                
shuffle = new Shuffle$thisopts );
                
$this.dataSHUFFLEshuffle );
            }

            if ( 
typeof opts === 'string' && shuffleopts ] ) {
                
shuffleopts ].applyshuffleargs );
            }
        });
    };


// You can return `undefined` from the `by` function to revert to DOM order
// This plugin does NOT return a jQuery object. It returns a plain array because
// jQuery sorts everything in DOM order.
    
$.fn.sorted = function(options) {
        var 
opts = $.extend({}, $.fn.sorted.defaultsoptions),
            
arr this.get(),
            
revert false;

        if ( !
arr.length ) {
            return [];
        }

        if ( 
opts.randomize ) {
            return $.
fn.sorted.randomizearr );
        }

        
// Sort the elements by the opts.by function.
        // If we don't have opts.by, default to DOM order
        
if (opts.by !== $.noop && opts.by !== null && opts.by !== undefined) {
            
arr.sort(function(ab) {

                
// Exit early if we already know we want to revert
                
if ( revert ) {
                    return 
0;
                }

                var 
valA opts.by($(a)),
                    
valB opts.by($(b));

                
// If both values are undefined, use the DOM order
                
if ( valA === undefined && valB === undefined ) {
                    
revert true;
                    return 
0;
                }

                if ( 
valA === 'sortFirst' || valB === 'sortLast' ) {
                    return -
1;
                }

                if ( 
valA === 'sortLast' || valB === 'sortFirst' ) {
                    return 
1;
                }

                return (
valA valB) ? -:
                    (
valA valB) ? 0;
            });
        }

        
// Revert to the original array if necessary
        
if ( revert ) {
            return 
this.get();
        }

        if ( 
opts.reverse ) {
            
arr.reverse();
        }

        return 
arr;
    };


    $.
fn.sorted.defaults = {
        
reversefalse// Use array.reverse() to reverse the results
        
bynull// Sorting function
        
randomizefalse // If true, this will skip the sorting and return a randomized order in the array
    
};


// http://stackoverflow.com/a/962890/373422
    
$.fn.sorted.randomize = function( array ) {
        var 
top = array.length,
            
tmpcurrent;

        if ( !
top ) {
            return array;
        }

        while ( --
top ) {
            
current Math.floorMath.random() * (top 1) );
            
tmp = array[ current ];
            array[ 
current ] = array[ top ];
            array[ 
top ] = tmp;
        }

        return array;
    };

    return 
Shuffle;

});
?>
Онлайн: 1
Реклама