Refactor all the things.

Removed shrink, shrunk, filter, and filtered events.
pull/56/head
Glen Cheney 10 years ago
parent c9105289e1
commit 36fad3200a

@ -3,7 +3,7 @@ destination: ./_site
plugins: ./_plugins
layouts: ./_layouts
include: ['.htaccess']
exclude: ['_scss', 'temp', 'node_modules', 'src']
exclude: ['_scss', 'temp', 'node_modules', 'src', 'bower_components']
permalink: /:title

@ -140,10 +140,6 @@ var Shuffle = function( element, options ) {
Shuffle.EventType = {
LOADING: 'loading',
DONE: 'done',
SHRINK: 'shrink',
SHRUNK: 'shrunk',
FILTER: 'filter',
FILTERED: 'filtered',
SORTED: 'sorted',
LAYOUT: 'layout',
REMOVED: 'removed'
@ -239,21 +235,18 @@ Shuffle._getOuterHeight = function( element, includeMargins ) {
/**
* 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.
* @param {Function} callback A function which will be called while transition
* is set to 0ms.
* @param {Object} [context] Optional context for the callback function.
* @private
*/
Shuffle._skipTransition = function( element, property, value ) {
Shuffle._skipTransition = function( element, callback, context ) {
var duration = element.style[ TRANSITION_DURATION ];
// Set the duration to zero so it happens immediately
element.style[ TRANSITION_DURATION ] = '0ms'; // ms needed for firefox!
if ( $.isFunction( property ) ) {
property();
} else {
element.style[ property ] = value;
}
callback.call( context );
// Force reflow
var reflow = element.offsetWidth;
@ -270,14 +263,8 @@ Shuffle.prototype = {
_init : function() {
var self = this;
self._layoutList = [];
self._shrinkList = [];
self._setVars();
// Zero out all columns
self._resetCols();
// Add classes and invalidate styles
this.$el.addClass( Shuffle.ClassName.BASE );
@ -378,8 +365,6 @@ Shuffle.prototype = {
category = category || this.lastFilter;
$collection = $collection || this.$items;
this._fire( Shuffle.EventType.FILTER );
var set = this._getFilteredSets( category, $collection );
// Individually add/remove concealed/filtered classes
@ -639,13 +624,11 @@ Shuffle.prototype = {
* 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( items, fn, isOnlyPosition ) {
_layout : function( items, isOnlyPosition ) {
var self = this;
fn = fn || self._filterEnd;
var added = 0;
$.each(items, function(index, item) {
var $item = $(item);
@ -666,19 +649,23 @@ Shuffle.prototype = {
$item: $item,
x: pos.x,
y: pos.y,
scale: DEFAULT_SCALE
scale: DEFAULT_SCALE,
opacity: isOnlyPosition ? 0 : 1,
skipTransition: !!isOnlyPosition,
callfront: function() {
if ( !isOnlyPosition ) {
$item.css( 'visibility', 'visible' );
}
},
callback: function() {
if ( isOnlyPosition ) {
$item.css( 'visibility', 'hidden' );
}
}
};
if ( isOnlyPosition ) {
transitionObj.skipTransition = true;
transitionObj.opacity = 0;
} else {
transitionObj.opacity = 1;
transitionObj.callback = fn;
}
added++;
self.styleQueue.push( transitionObj );
self._layoutList.push( $item[0] );
});
// `_layout` always happens after `_shrink`, so it's safe to process the style
@ -687,15 +674,18 @@ Shuffle.prototype = {
// A call to layout happened, but none of the newly filtered items will
// change position. Asynchronously fire the callback here.
if ( items.length > 0 && self._layoutList.length === 0 ) {
self._layoutEnd( fn );
if ( items.length > 0 && added === 0 ) {
self._layoutEnd();
}
// Adjust the height of the container
self._setContainerSize();
},
// Reset columns.
/**
* Zeros out the y columns array, which is used to determine item placement.
* @private
*/
_resetCols : function() {
var i = this.cols;
this.colYs = [];
@ -704,11 +694,6 @@ Shuffle.prototype = {
}
},
_reLayout : function() {
this._resetCols();
this.sort( this.lastSort, true );
},
_getItemPosition : function( $item ) {
var self = this;
var itemWidth = Shuffle._getOuterWidth( $item[0], true );
@ -750,7 +735,7 @@ Shuffle.prototype = {
}
},
// worker method that places item in the columnSet with the the minY
// TODO: Cleanup and combine with _getItemPosition.
_placeItem : function( $item, setY ) {
// get the minimum Y value from the columns
var self = this,
@ -786,23 +771,13 @@ Shuffle.prototype = {
/**
* Hides the elements that don't match our filter.
* @param {jQuery} $collection jQuery collection to shrink.
* @param {Function} fn Callback function.
* @private
*/
_shrink : function( $collection, fn ) {
var self = this,
$concealed = $collection || self._getConcealedItems();
fn = fn || self._shrinkEnd;
// Abort if no items
if ( !$concealed.length ) {
return;
}
self._fire( Shuffle.EventType.SHRINK );
_shrink : function( $collection ) {
var self = this;
var $concealed = $collection || self._getConcealedItems();
$concealed.each(function() {
$.each($concealed, function() {
var $item = $(this);
var itemData = $item.data();
var alreadyShrunk = itemData.scale === CONCEALED_SCALE;
@ -820,11 +795,12 @@ Shuffle.prototype = {
y: itemData.position.y,
scale : CONCEALED_SCALE,
opacity: 0,
callback: fn
callback: function() {
$item.css( 'visibility', 'hidden' );
}
};
self.styleQueue.push( transitionObj );
self._shrinkList.push( $item[0] );
});
},
@ -842,7 +818,7 @@ Shuffle.prototype = {
return;
}
this.resized();
this.update();
},
@ -860,39 +836,31 @@ Shuffle.prototype = {
styles.top = opts.y;
}
// Show the item if its opacity will be 1.
if ( opts.opacity === 1 ) {
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
* @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._getStylesForTransition( opts );
this._startItemAnimation( opts.$item, styles, opts.callback );
this._startItemAnimation( opts.$item, styles, opts.callfront || $.noop, opts.callback || $.noop );
},
_startItemAnimation : function( $item, styles, callback ) {
var willBeVisible = styles.opacity === 1;
var complete = $.proxy( this._handleItemAnimationEnd, this,
callback || $.noop, $item[0], willBeVisible );
_startItemAnimation : function( $item, styles, callfront, callback ) {
callfront();
// Use CSS Transforms if we have them
if ( this.supported ) {
@ -903,103 +871,76 @@ Shuffle.prototype = {
if ( this.initialized ) {
// Namespaced because the reveal appended function also wants to know
// about the transition end event.
$item.on( TRANSITIONEND + '.shuffleitem', complete );
$item.on( TRANSITIONEND, function( evt ) {
// Make sure this event handler has not bubbled up from a child.
if ( evt.target === evt.currentTarget ) {
callback();
}
});
} else {
complete();
callback();
}
// 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.stop( true ).animate( styles, this.speed, 'swing', complete );
}
},
_handleItemAnimationEnd : function( callback, item, willBeVisible, evt ) {
// Make sure this event handler has not bubbled up from a child.
if ( evt ) {
if ( evt.target === item ) {
$( item ).off( '.shuffleitem' );
} else {
return;
}
}
// Use timeouts so that all the items have been set to hidden before the
// callbacks are executed.
// Note(glen): I'm still not convinced this is the best way to handle firing
// a callback when all items have finished.
if ( this._layoutList.length > 0 && $.inArray( item, this._layoutList ) > -1 ) {
this._layoutEnd( callback );
this._layoutList.length = 0;
} else if ( this._shrinkList.length > 0 && $.inArray( item, this._shrinkList ) > -1 ) {
this._shrinkList.length = 0;
setTimeout( $.proxy( callback, this ), 0 );
}
if ( !willBeVisible ) {
item.style.visibility = 'hidden';
$item.stop( true ).animate( styles, this.speed, 'swing', callback );
}
},
_processStyleQueue : function() {
var self = this;
var $transitions = $();
$.each(this.styleQueue, function(i, transitionObj) {
if ( transitionObj.skipTransition ) {
Shuffle._skipTransition(transitionObj.$item[0], function() {
transitionObj.$item.css( self._getStylesForTransition( transitionObj ) );
});
self._styleImmediately( transitionObj );
} else {
$transitions = $transitions.add( transitionObj.$item );
self._transition( transitionObj );
}
});
if ( $transitions.length > 0 ) {
if ( this.initialized ) {
// TODO: Transitioning flag.
this._whenCollectionDone( $transitions, TRANSITIONEND, this._layoutEnd );
} else {
this._layoutEnd();
}
}
// Remove everything in the style queue
self.styleQueue.length = 0;
},
_shrinkEnd : function() {
this._fire( Shuffle.EventType.SHRUNK );
_styleImmediately : function( opts ) {
Shuffle._skipTransition(opts.$item[0], function() {
opts.$item.css( this._getStylesForTransition( opts ) );
}, this);
},
_filterEnd : function() {
this._fire( Shuffle.EventType.FILTERED );
_layoutEnd : function() {
setTimeout($.proxy( this._fire, this, Shuffle.EventType.LAYOUT ), 0);
},
_sortEnd : function() {
this._fire( Shuffle.EventType.SORTED );
},
_layoutEnd : function( callback ) {
setTimeout($.proxy(function () {
this._fire( Shuffle.EventType.LAYOUT );
callback.call( this );
}, this), 0);
},
_addItems : function( $newItems, animateIn, isSequential ) {
_addItems : function( $newItems, addToEnd, isSequential ) {
// Add classes and set initial positions.
this._initItems( $newItems );
// Add transition to each item.
this._setTransitions( $newItems );
this.$items = this._getItems();
// Hide all items
// $newItems.css('opacity', 0);
// Update the list of
this.$items = this._getItems();
// Shrink all items (without transitions).
this._shrink( $newItems, $.noop );
this._shrink( $newItems );
$.each(this.styleQueue, function(i, transitionObj) {
transitionObj.skipTransition = true;
});
this._processStyleQueue();
if ( this.supported && animateIn ) {
if ( addToEnd ) {
this._addItemsToEnd( $newItems, isSequential );
} else {
this.shuffle( this.lastFilter );
@ -1017,7 +958,7 @@ Shuffle.prototype = {
this._layout( passed, null, true );
if ( isSequential ) {
if ( isSequential && this.supported ) {
this._setSequentialDelay( passed );
}
@ -1044,6 +985,36 @@ Shuffle.prototype = {
},
/**
* Execute a function when an event has been triggered for every item in a collection.
* @param {jQuery} $collection Collection of elements.
* @param {string} eventName Event to listen for.
* @param {Function} callback Callback to execute when they're done.
* @private
*/
_whenCollectionDone : function( $collection, eventName, callback ) {
var done = 0;
var items = $collection.length;
var self = this;
function handleEventName( evt ) {
if ( evt.target === evt.currentTarget ) {
$( evt.target ).off( eventName );
done++;
// Execute callback if all items have emitted the correct event.
if ( done === items ) {
callback.call( self );
}
}
}
// Bind the event to all items.
$collection.on( eventName, handleEventName );
},
/**
* Public Methods
*/
@ -1054,9 +1025,7 @@ Shuffle.prototype = {
* @param {Object} [sortObj] A sort object which can sort the filtered set
*/
shuffle : function( category, sortObj ) {
var self = this;
if ( !self.enabled ) {
if ( !this.enabled ) {
return;
}
@ -1064,50 +1033,39 @@ Shuffle.prototype = {
category = ALL_ITEMS;
}
self._filter( category );
this._filter( category );
// How many filtered elements?
self._updateItemCount();
this._updateItemCount();
// Shrink each concealed item
self._shrink();
this._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();
this.sort( sortObj );
},
/**
* Gets the .filtered elements, sorts them, and passes them to layout
*
* 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( opts, fromFilter ) {
var self = this,
items = self._getFilteredItems().sorted(opts);
sort : function( opts ) {
this._resetCols();
if ( !fromFilter ) {
self._resetCols();
}
var sortOptions = opts || this.lastSort;
var items = this._getFilteredItems().sorted( sortOptions );
self._layout(items, function() {
if (fromFilter) {
self._filterEnd();
}
self._sortEnd();
});
this._layout( items );
self.lastSort = opts;
this.lastSort = opts;
},
/**
* Relayout everything
* Reposition everything.
* @param {boolean} isOnlyLayout If true, column and gutter widths won't be
* recalculated.
*/
resized : function( isOnlyLayout ) {
update : function( isOnlyLayout ) {
if ( this.enabled ) {
if ( !isOnlyLayout ) {
@ -1116,7 +1074,7 @@ Shuffle.prototype = {
}
// Layout items
this._reLayout();
this.sort();
}
},
@ -1129,22 +1087,15 @@ Shuffle.prototype = {
this.update( true );
},
update : function( isOnlyLayout ) {
this.resized( isOnlyLayout );
},
/**
* 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
* @param {boolean} [addToEnd=false] If true, new items will be added to the end / bottom
* of the items. If not true, items will be mixed in with the current sort order.
* @param {boolean} [isSequential=true] If false, new items won't sequentially fade in
*/
appended : function( $newItems, animateIn, isSequential ) {
// True if undefined
animateIn = animateIn === false ? false : true;
isSequential = isSequential === false ? false : true;
this._addItems( $newItems, animateIn, isSequential );
appended : function( $newItems, addToEnd, isSequential ) {
this._addItems( $newItems, addToEnd === true, isSequential !== false );
},
/**
@ -1177,21 +1128,21 @@ Shuffle.prototype = {
return;
}
var self = this;
// Hide collection first
self._shrink( $collection, function() {
var shuffle = this;
// Hide collection first.
this._shrink( $collection );
this._whenCollectionDone( $collection, TRANSITIONEND, function() {
var self = 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._fire( Shuffle.EventType.REMOVED, [ $collection, shuffle ] );
self.$items = self._getItems();
self.layout();
self._updateItemCount();
self._fire( Shuffle.EventType.REMOVED, [ $collection, self ] );
// Let it get garbage collected
$collection = null;
@ -1199,9 +1150,7 @@ Shuffle.prototype = {
});
// Process changes
self._processStyleQueue();
return self;
this._processStyleQueue();
},
/**

File diff suppressed because one or more lines are too long

@ -146,10 +146,6 @@ var Shuffle = function( element, options ) {
Shuffle.EventType = {
LOADING: 'loading',
DONE: 'done',
SHRINK: 'shrink',
SHRUNK: 'shrunk',
FILTER: 'filter',
FILTERED: 'filtered',
SORTED: 'sorted',
LAYOUT: 'layout',
REMOVED: 'removed'
@ -245,21 +241,18 @@ Shuffle._getOuterHeight = function( element, includeMargins ) {
/**
* 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.
* @param {Function} callback A function which will be called while transition
* is set to 0ms.
* @param {Object} [context] Optional context for the callback function.
* @private
*/
Shuffle._skipTransition = function( element, property, value ) {
Shuffle._skipTransition = function( element, callback, context ) {
var duration = element.style[ TRANSITION_DURATION ];
// Set the duration to zero so it happens immediately
element.style[ TRANSITION_DURATION ] = '0ms'; // ms needed for firefox!
if ( $.isFunction( property ) ) {
property();
} else {
element.style[ property ] = value;
}
callback.call( context );
// Force reflow
var reflow = element.offsetWidth;
@ -276,14 +269,8 @@ Shuffle.prototype = {
_init : function() {
var self = this;
self._layoutList = [];
self._shrinkList = [];
self._setVars();
// Zero out all columns
self._resetCols();
// Add classes and invalidate styles
this.$el.addClass( Shuffle.ClassName.BASE );
@ -384,8 +371,6 @@ Shuffle.prototype = {
category = category || this.lastFilter;
$collection = $collection || this.$items;
this._fire( Shuffle.EventType.FILTER );
var set = this._getFilteredSets( category, $collection );
// Individually add/remove concealed/filtered classes
@ -645,13 +630,11 @@ Shuffle.prototype = {
* 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( items, fn, isOnlyPosition ) {
_layout : function( items, isOnlyPosition ) {
var self = this;
fn = fn || self._filterEnd;
var added = 0;
$.each(items, function(index, item) {
var $item = $(item);
@ -672,19 +655,23 @@ Shuffle.prototype = {
$item: $item,
x: pos.x,
y: pos.y,
scale: DEFAULT_SCALE
scale: DEFAULT_SCALE,
opacity: isOnlyPosition ? 0 : 1,
skipTransition: !!isOnlyPosition,
callfront: function() {
if ( !isOnlyPosition ) {
$item.css( 'visibility', 'visible' );
}
},
callback: function() {
if ( isOnlyPosition ) {
$item.css( 'visibility', 'hidden' );
}
}
};
if ( isOnlyPosition ) {
transitionObj.skipTransition = true;
transitionObj.opacity = 0;
} else {
transitionObj.opacity = 1;
transitionObj.callback = fn;
}
added++;
self.styleQueue.push( transitionObj );
self._layoutList.push( $item[0] );
});
// `_layout` always happens after `_shrink`, so it's safe to process the style
@ -693,15 +680,18 @@ Shuffle.prototype = {
// A call to layout happened, but none of the newly filtered items will
// change position. Asynchronously fire the callback here.
if ( items.length > 0 && self._layoutList.length === 0 ) {
self._layoutEnd( fn );
if ( items.length > 0 && added === 0 ) {
self._layoutEnd();
}
// Adjust the height of the container
self._setContainerSize();
},
// Reset columns.
/**
* Zeros out the y columns array, which is used to determine item placement.
* @private
*/
_resetCols : function() {
var i = this.cols;
this.colYs = [];
@ -710,11 +700,6 @@ Shuffle.prototype = {
}
},
_reLayout : function() {
this._resetCols();
this.sort( this.lastSort, true );
},
_getItemPosition : function( $item ) {
var self = this;
var itemWidth = Shuffle._getOuterWidth( $item[0], true );
@ -756,7 +741,7 @@ Shuffle.prototype = {
}
},
// worker method that places item in the columnSet with the the minY
// TODO: Cleanup and combine with _getItemPosition.
_placeItem : function( $item, setY ) {
// get the minimum Y value from the columns
var self = this,
@ -792,23 +777,13 @@ Shuffle.prototype = {
/**
* Hides the elements that don't match our filter.
* @param {jQuery} $collection jQuery collection to shrink.
* @param {Function} fn Callback function.
* @private
*/
_shrink : function( $collection, fn ) {
var self = this,
$concealed = $collection || self._getConcealedItems();
fn = fn || self._shrinkEnd;
// Abort if no items
if ( !$concealed.length ) {
return;
}
self._fire( Shuffle.EventType.SHRINK );
_shrink : function( $collection ) {
var self = this;
var $concealed = $collection || self._getConcealedItems();
$concealed.each(function() {
$.each($concealed, function() {
var $item = $(this);
var itemData = $item.data();
var alreadyShrunk = itemData.scale === CONCEALED_SCALE;
@ -826,11 +801,12 @@ Shuffle.prototype = {
y: itemData.position.y,
scale : CONCEALED_SCALE,
opacity: 0,
callback: fn
callback: function() {
$item.css( 'visibility', 'hidden' );
}
};
self.styleQueue.push( transitionObj );
self._shrinkList.push( $item[0] );
});
},
@ -848,7 +824,7 @@ Shuffle.prototype = {
return;
}
this.resized();
this.update();
},
@ -866,39 +842,31 @@ Shuffle.prototype = {
styles.top = opts.y;
}
// Show the item if its opacity will be 1.
if ( opts.opacity === 1 ) {
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
* @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._getStylesForTransition( opts );
this._startItemAnimation( opts.$item, styles, opts.callback );
this._startItemAnimation( opts.$item, styles, opts.callfront || $.noop, opts.callback || $.noop );
},
_startItemAnimation : function( $item, styles, callback ) {
var willBeVisible = styles.opacity === 1;
var complete = $.proxy( this._handleItemAnimationEnd, this,
callback || $.noop, $item[0], willBeVisible );
_startItemAnimation : function( $item, styles, callfront, callback ) {
callfront();
// Use CSS Transforms if we have them
if ( this.supported ) {
@ -909,103 +877,76 @@ Shuffle.prototype = {
if ( this.initialized ) {
// Namespaced because the reveal appended function also wants to know
// about the transition end event.
$item.on( TRANSITIONEND + '.shuffleitem', complete );
$item.on( TRANSITIONEND, function( evt ) {
// Make sure this event handler has not bubbled up from a child.
if ( evt.target === evt.currentTarget ) {
callback();
}
});
} else {
complete();
callback();
}
// 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.stop( true ).animate( styles, this.speed, 'swing', complete );
}
},
_handleItemAnimationEnd : function( callback, item, willBeVisible, evt ) {
// Make sure this event handler has not bubbled up from a child.
if ( evt ) {
if ( evt.target === item ) {
$( item ).off( '.shuffleitem' );
} else {
return;
}
}
// Use timeouts so that all the items have been set to hidden before the
// callbacks are executed.
// Note(glen): I'm still not convinced this is the best way to handle firing
// a callback when all items have finished.
if ( this._layoutList.length > 0 && $.inArray( item, this._layoutList ) > -1 ) {
this._layoutEnd( callback );
this._layoutList.length = 0;
} else if ( this._shrinkList.length > 0 && $.inArray( item, this._shrinkList ) > -1 ) {
this._shrinkList.length = 0;
setTimeout( $.proxy( callback, this ), 0 );
}
if ( !willBeVisible ) {
item.style.visibility = 'hidden';
$item.stop( true ).animate( styles, this.speed, 'swing', callback );
}
},
_processStyleQueue : function() {
var self = this;
var $transitions = $();
$.each(this.styleQueue, function(i, transitionObj) {
if ( transitionObj.skipTransition ) {
Shuffle._skipTransition(transitionObj.$item[0], function() {
transitionObj.$item.css( self._getStylesForTransition( transitionObj ) );
});
self._styleImmediately( transitionObj );
} else {
$transitions = $transitions.add( transitionObj.$item );
self._transition( transitionObj );
}
});
if ( $transitions.length > 0 ) {
if ( this.initialized ) {
// TODO: Transitioning flag.
this._whenCollectionDone( $transitions, TRANSITIONEND, this._layoutEnd );
} else {
this._layoutEnd();
}
}
// Remove everything in the style queue
self.styleQueue.length = 0;
},
_shrinkEnd : function() {
this._fire( Shuffle.EventType.SHRUNK );
_styleImmediately : function( opts ) {
Shuffle._skipTransition(opts.$item[0], function() {
opts.$item.css( this._getStylesForTransition( opts ) );
}, this);
},
_filterEnd : function() {
this._fire( Shuffle.EventType.FILTERED );
_layoutEnd : function() {
setTimeout($.proxy( this._fire, this, Shuffle.EventType.LAYOUT ), 0);
},
_sortEnd : function() {
this._fire( Shuffle.EventType.SORTED );
},
_layoutEnd : function( callback ) {
setTimeout($.proxy(function () {
this._fire( Shuffle.EventType.LAYOUT );
callback.call( this );
}, this), 0);
},
_addItems : function( $newItems, animateIn, isSequential ) {
_addItems : function( $newItems, addToEnd, isSequential ) {
// Add classes and set initial positions.
this._initItems( $newItems );
// Add transition to each item.
this._setTransitions( $newItems );
this.$items = this._getItems();
// Hide all items
// $newItems.css('opacity', 0);
// Update the list of
this.$items = this._getItems();
// Shrink all items (without transitions).
this._shrink( $newItems, $.noop );
this._shrink( $newItems );
$.each(this.styleQueue, function(i, transitionObj) {
transitionObj.skipTransition = true;
});
this._processStyleQueue();
if ( this.supported && animateIn ) {
if ( addToEnd ) {
this._addItemsToEnd( $newItems, isSequential );
} else {
this.shuffle( this.lastFilter );
@ -1023,7 +964,7 @@ Shuffle.prototype = {
this._layout( passed, null, true );
if ( isSequential ) {
if ( isSequential && this.supported ) {
this._setSequentialDelay( passed );
}
@ -1050,6 +991,36 @@ Shuffle.prototype = {
},
/**
* Execute a function when an event has been triggered for every item in a collection.
* @param {jQuery} $collection Collection of elements.
* @param {string} eventName Event to listen for.
* @param {Function} callback Callback to execute when they're done.
* @private
*/
_whenCollectionDone : function( $collection, eventName, callback ) {
var done = 0;
var items = $collection.length;
var self = this;
function handleEventName( evt ) {
if ( evt.target === evt.currentTarget ) {
$( evt.target ).off( eventName );
done++;
// Execute callback if all items have emitted the correct event.
if ( done === items ) {
callback.call( self );
}
}
}
// Bind the event to all items.
$collection.on( eventName, handleEventName );
},
/**
* Public Methods
*/
@ -1060,9 +1031,7 @@ Shuffle.prototype = {
* @param {Object} [sortObj] A sort object which can sort the filtered set
*/
shuffle : function( category, sortObj ) {
var self = this;
if ( !self.enabled ) {
if ( !this.enabled ) {
return;
}
@ -1070,50 +1039,39 @@ Shuffle.prototype = {
category = ALL_ITEMS;
}
self._filter( category );
this._filter( category );
// How many filtered elements?
self._updateItemCount();
this._updateItemCount();
// Shrink each concealed item
self._shrink();
this._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();
this.sort( sortObj );
},
/**
* Gets the .filtered elements, sorts them, and passes them to layout
*
* 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( opts, fromFilter ) {
var self = this,
items = self._getFilteredItems().sorted(opts);
sort : function( opts ) {
this._resetCols();
if ( !fromFilter ) {
self._resetCols();
}
var sortOptions = opts || this.lastSort;
var items = this._getFilteredItems().sorted( sortOptions );
self._layout(items, function() {
if (fromFilter) {
self._filterEnd();
}
self._sortEnd();
});
this._layout( items );
self.lastSort = opts;
this.lastSort = opts;
},
/**
* Relayout everything
* Reposition everything.
* @param {boolean} isOnlyLayout If true, column and gutter widths won't be
* recalculated.
*/
resized : function( isOnlyLayout ) {
update : function( isOnlyLayout ) {
if ( this.enabled ) {
if ( !isOnlyLayout ) {
@ -1122,7 +1080,7 @@ Shuffle.prototype = {
}
// Layout items
this._reLayout();
this.sort();
}
},
@ -1135,22 +1093,15 @@ Shuffle.prototype = {
this.update( true );
},
update : function( isOnlyLayout ) {
this.resized( isOnlyLayout );
},
/**
* 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
* @param {boolean} [addToEnd=false] If true, new items will be added to the end / bottom
* of the items. If not true, items will be mixed in with the current sort order.
* @param {boolean} [isSequential=true] If false, new items won't sequentially fade in
*/
appended : function( $newItems, animateIn, isSequential ) {
// True if undefined
animateIn = animateIn === false ? false : true;
isSequential = isSequential === false ? false : true;
this._addItems( $newItems, animateIn, isSequential );
appended : function( $newItems, addToEnd, isSequential ) {
this._addItems( $newItems, addToEnd === true, isSequential !== false );
},
/**
@ -1183,21 +1134,21 @@ Shuffle.prototype = {
return;
}
var self = this;
// Hide collection first
self._shrink( $collection, function() {
var shuffle = this;
// Hide collection first.
this._shrink( $collection );
this._whenCollectionDone( $collection, TRANSITIONEND, function() {
var self = 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._fire( Shuffle.EventType.REMOVED, [ $collection, shuffle ] );
self.$items = self._getItems();
self.layout();
self._updateItemCount();
self._fire( Shuffle.EventType.REMOVED, [ $collection, self ] );
// Let it get garbage collected
$collection = null;
@ -1205,9 +1156,7 @@ Shuffle.prototype = {
});
// Process changes
self._processStyleQueue();
return self;
this._processStyleQueue();
},
/**

File diff suppressed because one or more lines are too long

@ -123,10 +123,6 @@ var Shuffle = function( element, options ) {
Shuffle.EventType = {
LOADING: 'loading',
DONE: 'done',
SHRINK: 'shrink',
SHRUNK: 'shrunk',
FILTER: 'filter',
FILTERED: 'filtered',
SORTED: 'sorted',
LAYOUT: 'layout',
REMOVED: 'removed'
@ -222,21 +218,18 @@ Shuffle._getOuterHeight = function( element, includeMargins ) {
/**
* 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.
* @param {Function} callback A function which will be called while transition
* is set to 0ms.
* @param {Object} [context] Optional context for the callback function.
* @private
*/
Shuffle._skipTransition = function( element, property, value ) {
Shuffle._skipTransition = function( element, callback, context ) {
var duration = element.style[ TRANSITION_DURATION ];
// Set the duration to zero so it happens immediately
element.style[ TRANSITION_DURATION ] = '0ms'; // ms needed for firefox!
if ( $.isFunction( property ) ) {
property();
} else {
element.style[ property ] = value;
}
callback.call( context );
// Force reflow
var reflow = element.offsetWidth;
@ -253,14 +246,8 @@ Shuffle.prototype = {
_init : function() {
var self = this;
self._layoutList = [];
self._shrinkList = [];
self._setVars();
// Zero out all columns
self._resetCols();
// Add classes and invalidate styles
this.$el.addClass( Shuffle.ClassName.BASE );
@ -361,8 +348,6 @@ Shuffle.prototype = {
category = category || this.lastFilter;
$collection = $collection || this.$items;
this._fire( Shuffle.EventType.FILTER );
var set = this._getFilteredSets( category, $collection );
// Individually add/remove concealed/filtered classes
@ -622,13 +607,11 @@ Shuffle.prototype = {
* 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( items, fn, isOnlyPosition ) {
_layout : function( items, isOnlyPosition ) {
var self = this;
fn = fn || self._filterEnd;
var added = 0;
$.each(items, function(index, item) {
var $item = $(item);
@ -649,19 +632,23 @@ Shuffle.prototype = {
$item: $item,
x: pos.x,
y: pos.y,
scale: DEFAULT_SCALE
scale: DEFAULT_SCALE,
opacity: isOnlyPosition ? 0 : 1,
skipTransition: !!isOnlyPosition,
callfront: function() {
if ( !isOnlyPosition ) {
$item.css( 'visibility', 'visible' );
}
},
callback: function() {
if ( isOnlyPosition ) {
$item.css( 'visibility', 'hidden' );
}
}
};
if ( isOnlyPosition ) {
transitionObj.skipTransition = true;
transitionObj.opacity = 0;
} else {
transitionObj.opacity = 1;
transitionObj.callback = fn;
}
added++;
self.styleQueue.push( transitionObj );
self._layoutList.push( $item[0] );
});
// `_layout` always happens after `_shrink`, so it's safe to process the style
@ -670,15 +657,18 @@ Shuffle.prototype = {
// A call to layout happened, but none of the newly filtered items will
// change position. Asynchronously fire the callback here.
if ( items.length > 0 && self._layoutList.length === 0 ) {
self._layoutEnd( fn );
if ( items.length > 0 && added === 0 ) {
self._layoutEnd();
}
// Adjust the height of the container
self._setContainerSize();
},
// Reset columns.
/**
* Zeros out the y columns array, which is used to determine item placement.
* @private
*/
_resetCols : function() {
var i = this.cols;
this.colYs = [];
@ -687,11 +677,6 @@ Shuffle.prototype = {
}
},
_reLayout : function() {
this._resetCols();
this.sort( this.lastSort, true );
},
_getItemPosition : function( $item ) {
var self = this;
var itemWidth = Shuffle._getOuterWidth( $item[0], true );
@ -733,7 +718,7 @@ Shuffle.prototype = {
}
},
// worker method that places item in the columnSet with the the minY
// TODO: Cleanup and combine with _getItemPosition.
_placeItem : function( $item, setY ) {
// get the minimum Y value from the columns
var self = this,
@ -769,23 +754,13 @@ Shuffle.prototype = {
/**
* Hides the elements that don't match our filter.
* @param {jQuery} $collection jQuery collection to shrink.
* @param {Function} fn Callback function.
* @private
*/
_shrink : function( $collection, fn ) {
var self = this,
$concealed = $collection || self._getConcealedItems();
fn = fn || self._shrinkEnd;
// Abort if no items
if ( !$concealed.length ) {
return;
}
self._fire( Shuffle.EventType.SHRINK );
_shrink : function( $collection ) {
var self = this;
var $concealed = $collection || self._getConcealedItems();
$concealed.each(function() {
$.each($concealed, function() {
var $item = $(this);
var itemData = $item.data();
var alreadyShrunk = itemData.scale === CONCEALED_SCALE;
@ -803,11 +778,12 @@ Shuffle.prototype = {
y: itemData.position.y,
scale : CONCEALED_SCALE,
opacity: 0,
callback: fn
callback: function() {
$item.css( 'visibility', 'hidden' );
}
};
self.styleQueue.push( transitionObj );
self._shrinkList.push( $item[0] );
});
},
@ -825,7 +801,7 @@ Shuffle.prototype = {
return;
}
this.resized();
this.update();
},
@ -843,39 +819,31 @@ Shuffle.prototype = {
styles.top = opts.y;
}
// Show the item if its opacity will be 1.
if ( opts.opacity === 1 ) {
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
* @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._getStylesForTransition( opts );
this._startItemAnimation( opts.$item, styles, opts.callback );
this._startItemAnimation( opts.$item, styles, opts.callfront || $.noop, opts.callback || $.noop );
},
_startItemAnimation : function( $item, styles, callback ) {
var willBeVisible = styles.opacity === 1;
var complete = $.proxy( this._handleItemAnimationEnd, this,
callback || $.noop, $item[0], willBeVisible );
_startItemAnimation : function( $item, styles, callfront, callback ) {
callfront();
// Use CSS Transforms if we have them
if ( this.supported ) {
@ -886,103 +854,76 @@ Shuffle.prototype = {
if ( this.initialized ) {
// Namespaced because the reveal appended function also wants to know
// about the transition end event.
$item.on( TRANSITIONEND + '.shuffleitem', complete );
$item.on( TRANSITIONEND, function( evt ) {
// Make sure this event handler has not bubbled up from a child.
if ( evt.target === evt.currentTarget ) {
callback();
}
});
} else {
complete();
callback();
}
// 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.stop( true ).animate( styles, this.speed, 'swing', complete );
}
},
_handleItemAnimationEnd : function( callback, item, willBeVisible, evt ) {
// Make sure this event handler has not bubbled up from a child.
if ( evt ) {
if ( evt.target === item ) {
$( item ).off( '.shuffleitem' );
} else {
return;
}
}
// Use timeouts so that all the items have been set to hidden before the
// callbacks are executed.
// Note(glen): I'm still not convinced this is the best way to handle firing
// a callback when all items have finished.
if ( this._layoutList.length > 0 && $.inArray( item, this._layoutList ) > -1 ) {
this._layoutEnd( callback );
this._layoutList.length = 0;
} else if ( this._shrinkList.length > 0 && $.inArray( item, this._shrinkList ) > -1 ) {
this._shrinkList.length = 0;
setTimeout( $.proxy( callback, this ), 0 );
}
if ( !willBeVisible ) {
item.style.visibility = 'hidden';
$item.stop( true ).animate( styles, this.speed, 'swing', callback );
}
},
_processStyleQueue : function() {
var self = this;
var $transitions = $();
$.each(this.styleQueue, function(i, transitionObj) {
if ( transitionObj.skipTransition ) {
Shuffle._skipTransition(transitionObj.$item[0], function() {
transitionObj.$item.css( self._getStylesForTransition( transitionObj ) );
});
self._styleImmediately( transitionObj );
} else {
$transitions = $transitions.add( transitionObj.$item );
self._transition( transitionObj );
}
});
if ( $transitions.length > 0 ) {
if ( this.initialized ) {
// TODO: Transitioning flag.
this._whenCollectionDone( $transitions, TRANSITIONEND, this._layoutEnd );
} else {
this._layoutEnd();
}
}
// Remove everything in the style queue
self.styleQueue.length = 0;
},
_shrinkEnd : function() {
this._fire( Shuffle.EventType.SHRUNK );
_styleImmediately : function( opts ) {
Shuffle._skipTransition(opts.$item[0], function() {
opts.$item.css( this._getStylesForTransition( opts ) );
}, this);
},
_filterEnd : function() {
this._fire( Shuffle.EventType.FILTERED );
_layoutEnd : function() {
setTimeout($.proxy( this._fire, this, Shuffle.EventType.LAYOUT ), 0);
},
_sortEnd : function() {
this._fire( Shuffle.EventType.SORTED );
},
_layoutEnd : function( callback ) {
setTimeout($.proxy(function () {
this._fire( Shuffle.EventType.LAYOUT );
callback.call( this );
}, this), 0);
},
_addItems : function( $newItems, animateIn, isSequential ) {
_addItems : function( $newItems, addToEnd, isSequential ) {
// Add classes and set initial positions.
this._initItems( $newItems );
// Add transition to each item.
this._setTransitions( $newItems );
this.$items = this._getItems();
// Hide all items
// $newItems.css('opacity', 0);
// Update the list of
this.$items = this._getItems();
// Shrink all items (without transitions).
this._shrink( $newItems, $.noop );
this._shrink( $newItems );
$.each(this.styleQueue, function(i, transitionObj) {
transitionObj.skipTransition = true;
});
this._processStyleQueue();
if ( this.supported && animateIn ) {
if ( addToEnd ) {
this._addItemsToEnd( $newItems, isSequential );
} else {
this.shuffle( this.lastFilter );
@ -1000,7 +941,7 @@ Shuffle.prototype = {
this._layout( passed, null, true );
if ( isSequential ) {
if ( isSequential && this.supported ) {
this._setSequentialDelay( passed );
}
@ -1027,6 +968,36 @@ Shuffle.prototype = {
},
/**
* Execute a function when an event has been triggered for every item in a collection.
* @param {jQuery} $collection Collection of elements.
* @param {string} eventName Event to listen for.
* @param {Function} callback Callback to execute when they're done.
* @private
*/
_whenCollectionDone : function( $collection, eventName, callback ) {
var done = 0;
var items = $collection.length;
var self = this;
function handleEventName( evt ) {
if ( evt.target === evt.currentTarget ) {
$( evt.target ).off( eventName );
done++;
// Execute callback if all items have emitted the correct event.
if ( done === items ) {
callback.call( self );
}
}
}
// Bind the event to all items.
$collection.on( eventName, handleEventName );
},
/**
* Public Methods
*/
@ -1037,9 +1008,7 @@ Shuffle.prototype = {
* @param {Object} [sortObj] A sort object which can sort the filtered set
*/
shuffle : function( category, sortObj ) {
var self = this;
if ( !self.enabled ) {
if ( !this.enabled ) {
return;
}
@ -1047,50 +1016,39 @@ Shuffle.prototype = {
category = ALL_ITEMS;
}
self._filter( category );
this._filter( category );
// How many filtered elements?
self._updateItemCount();
this._updateItemCount();
// Shrink each concealed item
self._shrink();
this._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();
this.sort( sortObj );
},
/**
* Gets the .filtered elements, sorts them, and passes them to layout
*
* 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( opts, fromFilter ) {
var self = this,
items = self._getFilteredItems().sorted(opts);
sort : function( opts ) {
this._resetCols();
if ( !fromFilter ) {
self._resetCols();
}
var sortOptions = opts || this.lastSort;
var items = this._getFilteredItems().sorted( sortOptions );
self._layout(items, function() {
if (fromFilter) {
self._filterEnd();
}
self._sortEnd();
});
this._layout( items );
self.lastSort = opts;
this.lastSort = opts;
},
/**
* Relayout everything
* Reposition everything.
* @param {boolean} isOnlyLayout If true, column and gutter widths won't be
* recalculated.
*/
resized : function( isOnlyLayout ) {
update : function( isOnlyLayout ) {
if ( this.enabled ) {
if ( !isOnlyLayout ) {
@ -1099,7 +1057,7 @@ Shuffle.prototype = {
}
// Layout items
this._reLayout();
this.sort();
}
},
@ -1112,22 +1070,15 @@ Shuffle.prototype = {
this.update( true );
},
update : function( isOnlyLayout ) {
this.resized( isOnlyLayout );
},
/**
* 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
* @param {boolean} [addToEnd=false] If true, new items will be added to the end / bottom
* of the items. If not true, items will be mixed in with the current sort order.
* @param {boolean} [isSequential=true] If false, new items won't sequentially fade in
*/
appended : function( $newItems, animateIn, isSequential ) {
// True if undefined
animateIn = animateIn === false ? false : true;
isSequential = isSequential === false ? false : true;
this._addItems( $newItems, animateIn, isSequential );
appended : function( $newItems, addToEnd, isSequential ) {
this._addItems( $newItems, addToEnd === true, isSequential !== false );
},
/**
@ -1160,21 +1111,21 @@ Shuffle.prototype = {
return;
}
var self = this;
// Hide collection first
self._shrink( $collection, function() {
var shuffle = this;
// Hide collection first.
this._shrink( $collection );
this._whenCollectionDone( $collection, TRANSITIONEND, function() {
var self = 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._fire( Shuffle.EventType.REMOVED, [ $collection, shuffle ] );
self.$items = self._getItems();
self.layout();
self._updateItemCount();
self._fire( Shuffle.EventType.REMOVED, [ $collection, self ] );
// Let it get garbage collected
$collection = null;
@ -1182,9 +1133,7 @@ Shuffle.prototype = {
});
// Process changes
self._processStyleQueue();
return self;
this._processStyleQueue();
},
/**

@ -212,42 +212,42 @@ describe('Shuffle.js', function() {
expect(shuffle.lastSort).toEqual(sortObj);
});
// it('can add items', function(done) {
// var $shuffle = $('#regular-shuffle');
// var shuffle = $shuffle.shuffle({
// speed: 100,
// group: 'black'
// }).data('shuffle');
// function first() {
// var $eleven = $('<div>', {
// 'class': 'item',
// 'data-age': 36,
// 'data-groups': '["ux", "black"]',
// id: 'item11',
// text: 'Person 11'
// });
// var $twelve = $('<div>', {
// 'class': 'item',
// 'data-age': 37,
// 'data-groups': '["strategy", "blue"]',
// id: 'item12',
// text: 'Person 12'
// });
// var $collection = $eleven.add($twelve);
// $shuffle.append($collection);
// shuffle.appended($collection);
// // Already 2 in the items, plus number 11.
// expect(shuffle.visibleItems).toBe(3);
// done();
// }
// $shuffle.one('done.shuffle', first);
// });
it('can add items', function(done) {
var $shuffle = $('#regular-shuffle');
var shuffle = $shuffle.shuffle({
speed: 100,
group: 'black'
}).data('shuffle');
function first() {
var $eleven = $('<div>', {
'class': 'item',
'data-age': 36,
'data-groups': '["ux", "black"]',
id: 'item11',
text: 'Person 11'
});
var $twelve = $('<div>', {
'class': 'item',
'data-age': 37,
'data-groups': '["strategy", "blue"]',
id: 'item12',
text: 'Person 12'
});
var $collection = $eleven.add($twelve);
$shuffle.append($collection);
shuffle.appended($collection);
// Already 2 in the items, plus number 11.
expect(shuffle.visibleItems).toBe(3);
done();
}
$shuffle.one('done.shuffle', first);
});
it('can call appended with different options', function() {
@ -263,9 +263,9 @@ describe('Shuffle.js', function() {
shuffle.appended(null, false, false);
expect(shuffle._addItems).toHaveBeenCalledWith(null, false, false);
shuffle.appended(null);
expect(shuffle._addItems).toHaveBeenCalledWith(null, true, true);
expect(shuffle._addItems).toHaveBeenCalledWith(null, false, true);
shuffle.appended(null, null, null);
expect(shuffle._addItems).toHaveBeenCalledWith(null, true, true);
expect(shuffle._addItems).toHaveBeenCalledWith(null, false, true);
});

Loading…
Cancel
Save