Update add items 3rd mode to mix in to the current set.

When the items are sorted, using the mix in method is much better
looking, but adding items to the end is better for infinite scrolling
and DOM order.
* Mix in.
* Add to end.
* Add to end with sequential delay.
pull/56/head
Glen Cheney 10 years ago
parent b96ff65dac
commit c9105289e1

@ -148,7 +148,8 @@ module.exports = function(grunt) {
'concat:main',
'concat:modernizr',
'uglify:main',
'uglify:modernizr'
'uglify:modernizr',
'test'
]);
});

@ -31,6 +31,14 @@ extraJS: [ "demos/adding-removing.js" ]
left: .5em;
}
.box::after {
content: 'Box SKU: ' attr(created);
position: absolute;
color: white;
bottom: .5em;
left: .5em;
}
.box.shuffle-item,
.box:first-child {
margin-left: 0;
@ -56,19 +64,37 @@ extraJS: [ "demos/adding-removing.js" ]
</section>
<section class="container">
<button id="randomize">Randomize</button>
<div style="margin-bottom: 10px;">
<span class="filter__label">Add mode:</span>
<select id="mode" class="sort-options">
<option value="end">Add to end</option>
<option selected value="end-sequential">Add to end with delay</option>
<option value="mix">Mix in with current</option>
</select>
</div>
<div class="pull-left">
<button id="add">Add 5 Boxes</button>
<button id="remove">Remove Some Boxes</button>
<button id="randomize">Randomize</button>
</div>
<div class="pull-right">
<span class="filter__label">Sort:</span>
<select id="sorter" class="sort-options">
<option value="dom">Default</option>
<option value="created">Box SKU</option>
<option value="random">Randomize</option>
</select>
</div>
</section>
<section class="container">
<div id="my-shuffle" class="items">
<div class="box"></div>
<div class="box h2 w2"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box w2"></div>
<div class="box"></div>
<div class="box" created="45"></div>
<div class="box h2 w2" created="19"></div>
<div class="box" created="66"></div>
<div class="box" created="148"></div>
<div class="box w2" created="99"></div>
<div class="box" created="3"></div>
</div>
</section>

@ -370,7 +370,7 @@ Shuffle.prototype = {
* 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
* @param {ArrayLike} [$collection] Optionally filter a collection. Defaults to
* all the items.
* @return {jQuery} Filtered items.
*/
@ -401,7 +401,7 @@ Shuffle.prototype = {
/**
* Returns an object containing the filtered and concealed elements.
* @param {string|Function} category Category or function to filter by.
* @param {jQuery} $items jQuery collection of items to filter.
* @param {ArrayLike.<Element>} $items A collection of items to filter.
* @return {!{filtered: jQuery, concealed: jQuery}}
* @private
*/
@ -417,7 +417,7 @@ Shuffle.prototype = {
// whether to hide it or not.
} else {
var self = this;
$items.each(function(i, el) {
$.each($items, function(i, el) {
var $item = $(el);
if ( self._doesPassFilter( category, $item ) ) {
$filtered = $filtered.add( $item );
@ -502,6 +502,11 @@ Shuffle.prototype = {
});
},
/**
* Sets a transition delay on a collection of elements, making each delay
* greater than the last.
* @param {ArrayLike.<Element>} $collection Array to iterate over.
*/
_setSequentialDelay : function( $collection ) {
var self = this;
@ -701,13 +706,7 @@ Shuffle.prototype = {
_reLayout : function() {
this._resetCols();
// If we've already sorted the elements, keep them sorted
if ( this.lastSort ) {
this.sort( this.lastSort, true );
} else {
this._layout( this._getFilteredItems().get(), this._filterEnd );
}
this.sort( this.lastSort, true );
},
_getItemPosition : function( $item ) {
@ -933,6 +932,8 @@ Shuffle.prototype = {
// 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;
@ -984,44 +985,55 @@ Shuffle.prototype = {
},
_addItems : function( $newItems, animateIn, isSequential ) {
var self = this;
this._initItems( $newItems );
this._setTransitions( $newItems );
this.$items = this._getItems();
if ( !self.supported ) {
animateIn = false;
}
// Hide all items
// $newItems.css('opacity', 0);
self._initItems( $newItems );
self._setTransitions( $newItems );
self.$items = self._getItems();
// Shrink all items (without transitions).
this._shrink( $newItems, $.noop );
$.each(this.styleQueue, function(i, transitionObj) {
transitionObj.skipTransition = true;
});
this._processStyleQueue();
// Hide all items
$newItems.css('opacity', 0);
if ( this.supported && animateIn ) {
this._addItemsToEnd( $newItems, isSequential );
} else {
this.shuffle( this.lastFilter );
}
},
_addItemsToEnd : function( $newItems, isSequential ) {
// Get ones that passed the current filter
var $passed = self._filter( null, $newItems );
var $passed = this._filter( null, $newItems );
var passed = $passed.get();
// How many filtered elements?
self._updateItemCount();
if ( animateIn ) {
self._layout( passed, null, true );
this._updateItemCount();
if ( isSequential ) {
self._setSequentialDelay( $passed );
}
this._layout( passed, null, true );
self._revealAppended( $passed );
} else {
self._layout( passed );
if ( isSequential ) {
this._setSequentialDelay( passed );
}
this._revealAppended( passed );
},
/**
* Triggers appended elements to fade in.
* @param {ArrayLike.<Element>} $newFilteredItems Collection of elements.
* @private
*/
_revealAppended : function( $newFilteredItems ) {
var self = this;
setTimeout(function() {
$newFilteredItems.each(function(i, el) {
$.each($newFilteredItems, function(i, el) {
self._transition({
$item: $(el),
opacity: 1,
@ -1257,6 +1269,8 @@ Shuffle.settings = {
},
offset: { top: 0, left: 0 },
revealAppendedDelay: 300,
lastSort: {},
lastFilter: ALL_ITEMS,
enabled: true,
destroyed: false,
initialized: false,

File diff suppressed because one or more lines are too long

@ -376,7 +376,7 @@ Shuffle.prototype = {
* 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
* @param {ArrayLike} [$collection] Optionally filter a collection. Defaults to
* all the items.
* @return {jQuery} Filtered items.
*/
@ -407,7 +407,7 @@ Shuffle.prototype = {
/**
* Returns an object containing the filtered and concealed elements.
* @param {string|Function} category Category or function to filter by.
* @param {jQuery} $items jQuery collection of items to filter.
* @param {ArrayLike.<Element>} $items A collection of items to filter.
* @return {!{filtered: jQuery, concealed: jQuery}}
* @private
*/
@ -423,7 +423,7 @@ Shuffle.prototype = {
// whether to hide it or not.
} else {
var self = this;
$items.each(function(i, el) {
$.each($items, function(i, el) {
var $item = $(el);
if ( self._doesPassFilter( category, $item ) ) {
$filtered = $filtered.add( $item );
@ -508,6 +508,11 @@ Shuffle.prototype = {
});
},
/**
* Sets a transition delay on a collection of elements, making each delay
* greater than the last.
* @param {ArrayLike.<Element>} $collection Array to iterate over.
*/
_setSequentialDelay : function( $collection ) {
var self = this;
@ -707,13 +712,7 @@ Shuffle.prototype = {
_reLayout : function() {
this._resetCols();
// If we've already sorted the elements, keep them sorted
if ( this.lastSort ) {
this.sort( this.lastSort, true );
} else {
this._layout( this._getFilteredItems().get(), this._filterEnd );
}
this.sort( this.lastSort, true );
},
_getItemPosition : function( $item ) {
@ -939,6 +938,8 @@ Shuffle.prototype = {
// 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;
@ -990,44 +991,55 @@ Shuffle.prototype = {
},
_addItems : function( $newItems, animateIn, isSequential ) {
var self = this;
this._initItems( $newItems );
this._setTransitions( $newItems );
this.$items = this._getItems();
if ( !self.supported ) {
animateIn = false;
}
// Hide all items
// $newItems.css('opacity', 0);
self._initItems( $newItems );
self._setTransitions( $newItems );
self.$items = self._getItems();
// Shrink all items (without transitions).
this._shrink( $newItems, $.noop );
$.each(this.styleQueue, function(i, transitionObj) {
transitionObj.skipTransition = true;
});
this._processStyleQueue();
// Hide all items
$newItems.css('opacity', 0);
if ( this.supported && animateIn ) {
this._addItemsToEnd( $newItems, isSequential );
} else {
this.shuffle( this.lastFilter );
}
},
_addItemsToEnd : function( $newItems, isSequential ) {
// Get ones that passed the current filter
var $passed = self._filter( null, $newItems );
var $passed = this._filter( null, $newItems );
var passed = $passed.get();
// How many filtered elements?
self._updateItemCount();
if ( animateIn ) {
self._layout( passed, null, true );
this._updateItemCount();
if ( isSequential ) {
self._setSequentialDelay( $passed );
}
this._layout( passed, null, true );
self._revealAppended( $passed );
} else {
self._layout( passed );
if ( isSequential ) {
this._setSequentialDelay( passed );
}
this._revealAppended( passed );
},
/**
* Triggers appended elements to fade in.
* @param {ArrayLike.<Element>} $newFilteredItems Collection of elements.
* @private
*/
_revealAppended : function( $newFilteredItems ) {
var self = this;
setTimeout(function() {
$newFilteredItems.each(function(i, el) {
$.each($newFilteredItems, function(i, el) {
self._transition({
$item: $(el),
opacity: 1,
@ -1263,6 +1275,8 @@ Shuffle.settings = {
},
offset: { top: 0, left: 0 },
revealAppendedDelay: 300,
lastSort: {},
lastFilter: ALL_ITEMS,
enabled: true,
destroyed: false,
initialized: false,

File diff suppressed because one or more lines are too long

@ -8,6 +8,9 @@ window.Manipulator = (function($) {
self.$el = $( element );
self.init();
this.addToEnd = true;
this.sequentialDelay = true;
};
Manipulator.prototype.init = function() {
@ -44,6 +47,8 @@ window.Manipulator = (function($) {
$('#add').on('click', $.proxy( self.onAddClick, self ));
$('#randomize').on('click', $.proxy( self.onRandomize, self ));
$('#remove').on('click', $.proxy( self.onRemoveClick, self ));
$('#sorter').on('change', $.proxy( self.onSortChange, self ));
$('#mode').on('change', $.proxy( self.onModeChange, self ));
// Show off some shuffle events
self.$el.on('removed.shuffle', function( evt, $collection, shuffle ) {
@ -74,6 +79,7 @@ window.Manipulator = (function($) {
random = Math.random();
box = document.createElement('div');
box.className = 'box';
box.setAttribute('created', this.getRandomInt(1, 150));
// Randomly add a class
if ( random > 0.8 ) {
@ -90,7 +96,7 @@ window.Manipulator = (function($) {
// Tell shuffle items have been appended.
// It expects a jQuery object as the parameter.
self.shuffle.appended( $items );
self.shuffle.appended( $items, this.addToEnd, this.sequentialDelay );
// or
// self.$el.shuffle('appended', $items );
};
@ -131,14 +137,43 @@ window.Manipulator = (function($) {
};
Manipulator.prototype.onRandomize = function() {
var self = this,
sortObj = {
randomize: true
};
$('#sorter').val('random').trigger('change');
};
self.shuffle.sort( sortObj );
// or
// self.$el.shuffle('sort', sortObj);
Manipulator.prototype.onSortChange = function(evt) {
var value = evt.target.value;
var opts = {};
// We're given the element wrapped in jQuery
if ( value === 'created' ) {
opts = {
by: function($el) {
return parseInt($el.attr('created'), 10);
}
};
} else if ( value === 'random' ) {
opts = {
randomize: true
};
}
// Filter elements
this.$el.shuffle('sort', opts);
};
Manipulator.prototype.onModeChange = function(evt) {
var value = evt.target.value;
if (value === 'end') {
this.addToEnd = true;
this.sequentialDelay = false;
} else if (value === 'end-sequential') {
this.addToEnd = true;
this.sequentialDelay = true;
} else if (value === 'mix') {
this.addToEnd = false;
this.sequentialDelay = false;
}
};
return Manipulator;

@ -353,7 +353,7 @@ Shuffle.prototype = {
* 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
* @param {ArrayLike} [$collection] Optionally filter a collection. Defaults to
* all the items.
* @return {jQuery} Filtered items.
*/
@ -384,7 +384,7 @@ Shuffle.prototype = {
/**
* Returns an object containing the filtered and concealed elements.
* @param {string|Function} category Category or function to filter by.
* @param {jQuery} $items jQuery collection of items to filter.
* @param {ArrayLike.<Element>} $items A collection of items to filter.
* @return {!{filtered: jQuery, concealed: jQuery}}
* @private
*/
@ -400,7 +400,7 @@ Shuffle.prototype = {
// whether to hide it or not.
} else {
var self = this;
$items.each(function(i, el) {
$.each($items, function(i, el) {
var $item = $(el);
if ( self._doesPassFilter( category, $item ) ) {
$filtered = $filtered.add( $item );
@ -485,6 +485,11 @@ Shuffle.prototype = {
});
},
/**
* Sets a transition delay on a collection of elements, making each delay
* greater than the last.
* @param {ArrayLike.<Element>} $collection Array to iterate over.
*/
_setSequentialDelay : function( $collection ) {
var self = this;
@ -684,13 +689,7 @@ Shuffle.prototype = {
_reLayout : function() {
this._resetCols();
// If we've already sorted the elements, keep them sorted
if ( this.lastSort ) {
this.sort( this.lastSort, true );
} else {
this._layout( this._getFilteredItems().get(), this._filterEnd );
}
this.sort( this.lastSort, true );
},
_getItemPosition : function( $item ) {
@ -916,6 +915,8 @@ Shuffle.prototype = {
// 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;
@ -967,44 +968,55 @@ Shuffle.prototype = {
},
_addItems : function( $newItems, animateIn, isSequential ) {
var self = this;
this._initItems( $newItems );
this._setTransitions( $newItems );
this.$items = this._getItems();
if ( !self.supported ) {
animateIn = false;
}
// Hide all items
// $newItems.css('opacity', 0);
self._initItems( $newItems );
self._setTransitions( $newItems );
self.$items = self._getItems();
// Shrink all items (without transitions).
this._shrink( $newItems, $.noop );
$.each(this.styleQueue, function(i, transitionObj) {
transitionObj.skipTransition = true;
});
this._processStyleQueue();
// Hide all items
$newItems.css('opacity', 0);
if ( this.supported && animateIn ) {
this._addItemsToEnd( $newItems, isSequential );
} else {
this.shuffle( this.lastFilter );
}
},
_addItemsToEnd : function( $newItems, isSequential ) {
// Get ones that passed the current filter
var $passed = self._filter( null, $newItems );
var $passed = this._filter( null, $newItems );
var passed = $passed.get();
// How many filtered elements?
self._updateItemCount();
if ( animateIn ) {
self._layout( passed, null, true );
this._updateItemCount();
if ( isSequential ) {
self._setSequentialDelay( $passed );
}
this._layout( passed, null, true );
self._revealAppended( $passed );
} else {
self._layout( passed );
if ( isSequential ) {
this._setSequentialDelay( passed );
}
this._revealAppended( passed );
},
/**
* Triggers appended elements to fade in.
* @param {ArrayLike.<Element>} $newFilteredItems Collection of elements.
* @private
*/
_revealAppended : function( $newFilteredItems ) {
var self = this;
setTimeout(function() {
$newFilteredItems.each(function(i, el) {
$.each($newFilteredItems, function(i, el) {
self._transition({
$item: $(el),
opacity: 1,
@ -1240,6 +1252,8 @@ Shuffle.settings = {
},
offset: { top: 0, left: 0 },
revealAppendedDelay: 300,
lastSort: {},
lastFilter: ALL_ITEMS,
enabled: true,
destroyed: false,
initialized: false,

@ -31,6 +31,7 @@
"loadFixtures": true,
"jasmine": true,
"expect": true,
"spyOn": true,
"$": true,
"Modernizr": true
}

@ -212,33 +212,60 @@ describe('Shuffle.js', function() {
expect(shuffle.lastSort).toEqual(sortObj);
});
it('can add items', function(done) {
// 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() {
var $shuffle = $('#regular-shuffle');
var shuffle = $shuffle.shuffle({
speed: 100
}).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'
});
spyOn(shuffle, '_addItems').and.callFake(function() {});
var $collection = $eleven.add($twelve);
done();
}
$shuffle.one('done.shuffle', first);
shuffle.appended(null, true, true);
expect(shuffle._addItems).toHaveBeenCalledWith(null, true, true);
shuffle.appended(null, false, false);
expect(shuffle._addItems).toHaveBeenCalledWith(null, false, false);
shuffle.appended(null);
expect(shuffle._addItems).toHaveBeenCalledWith(null, true, true);
shuffle.appended(null, null, null);
expect(shuffle._addItems).toHaveBeenCalledWith(null, true, true);
});
@ -251,9 +278,6 @@ describe('Shuffle.js', function() {
loadFixtures('regular.html');
});
afterEach(function() {
});
it('will catch empty jQuery objects', function() {
var $items = $();

@ -1,7 +1,6 @@
# Todos and other improvements
## Improvements
* TESTS!
* More JSDoc
* Create an `Item` class for shuffle items so they can handle storing values and more.
* Horizontal layout

Loading…
Cancel
Save