Added sorting ability, made plugin responsive, added advanced filtering method. Updated to Modernizr 2.6.2

pull/56/head
Glen Cheney 12 years ago
parent bbb4a3df36
commit fef5995995

@ -12,10 +12,7 @@ Settings you can change (these are the defaults)
```js
var options = {
itemWidth : 230, // Width of the grid item
marginTop : 20, // Top margin
marginRight: 20, // Right margin
key : 'all' // Which category to show
group : 'all' // Which category to show
speed : 800, // Speed of the transition (in milliseconds). 800 = .8 seconds
easing : 'ease-out' // css easing function to use
};
@ -25,30 +22,30 @@ $('#grid').shuffle(options);
The easing function is one of `default`, `linear`, `ease-in`, `ease-out`, `ease-in-out`, or `cubic-bezier`.
### The HTML
The html structure. The only real important thing here is the 'data-key' attribute. It has to be a [valid JSON](http://jsonlint.com/) array of strings.
The html structure. The only real important thing here is the 'data-groups' attribute. It has to be a [valid JSON](http://jsonlint.com/) array of strings.
```html
<div id="grid">
<div class="item" data-key='["photography"]'>
<img src="img/baseball.png" alt="" height="145" width="230" />
<div class="item" data-groups='["photography"]' data-date-created="2010-09-14" data-title="Baseball">
<img src="img/baseball.png" />
<div class="item-details">
<a href="#">Photography</a>
</div>
</div>
<div class="item" data-key='["wallpaper", "3d"]'>
<img src="img/tennis-ball.png" alt="" height="145" width="230" />
<div class="item" data-groups='["wallpaper", "3d"]' data-date-created="2011-08-14" data-title="Tennis">
<img src="img/tennis-ball.png" />
<div class="item-details">
<a href="#">3D Render, Wallpaper</a>
</div>
</div>
<div class="item" data-key='["3d", "wallpaper"]'>
<img src="img/imac.png" alt="" height="145" width="230" />
<div class="item" data-groups='["3d", "wallpaper"]' data-date-created="2009-05-27" data-title="iMac">
<img src="img/imac.png" />
<div class="item-details">
<a href="#">3D Render, Wallpaper</a>
</div>
</div>
<div class="item" data-key='["graphics"]'>
<img src="img/master-chief.png" alt="" height="145" width="230" />
<div class="item" data-groups='["graphics"]' data-date-created="2012-05-14" data-title="Master Chief">
<img src="img/master-chief.png" />
<div class="item-details">
<a href="#">Graphic Design</a>
</div>
@ -56,17 +53,26 @@ The html structure. The only real important thing here is the 'data-key' attribu
</div>
```
Shuffle takes the width, margin-top, and marigin-right from the `.item`.
```css
#grid .item {
width: 230px;
margin-top: 20px;
margin-right: 20px;
}
```
## How to "Shuffle"
Say you have this markup
Say you have this markup for your options
```html
<ul class="filter-options">
<li data-key="all" class="active">Most Recent</li>
<li data-key="wallpaper">Wallpapers</li>
<li data-key="graphics">Graphic Design</li>
<li data-key="photography">Photography</li>
<li data-key="3d">3D Renders</li>
<li data-key="motion">Motion Graphics</li>
<li data-group="all" class="active">Most Recent</li>
<li data-group="wallpaper">Wallpapers</li>
<li data-group="graphics">Graphic Design</li>
<li data-group="photography">Photography</li>
<li data-group="3d">3D Renders</li>
</ul>
```
And when you click on a li, you want the plugin to shuffle. Here's an example:
@ -84,29 +90,107 @@ $(document).ready(function(){
$this.addClass('active');
// Filter elements
$grid.shuffle($this.attr('data-key'));
$grid.shuffle($this.data('group'));
});
// instantiate the plugin
$('#grid').shuffle({
itemWidth : 230,
marginTop : 20,
marginRight: 20,
key : 'all',
group : 'all',
speed : 800,
easing : 'ease-out'
});
});
```
Events that get triggered: `shrink.shuffle`, `shrunk.shuffle`, `filter.shuffle`, and `filtered.shuffle`.
These events will be triggered at their respective times: `shrink.shuffle`, `shrunk.shuffle`, `filter.shuffle`, `filtered.shuffle`, and `sorted.shuffle`.
## Sorting
You can order the elements based off a function you supply. In the example above, each item has a `data-date-created` and `data-title` attribute. The filter buttons have a `data-sort` attribute with the value of the item&rsquo;s attribute. Then, with some JavaScript, we can get the correct attribute and provide a function to sort by.
```html
<li data-sort="title">Title</li>
```
```html
<div class="item" data-title="Baseball"></div>
```
```javascript
// Sorting options
$('.sort-options li').on('click', function() {
var $this = $(this),
$grid = $('#grid'),
sort = $this.data('sort'),
opts = {};
// Hide current label, show current label in title
$('.sort-options .active').removeClass('active');
$this.addClass('active');
// We're given the element wrapped in jQuery
if (sort === 'date-created') {
opts = {
by: function($el) {
return $el.data('date-created');
}
}
} else if (sort === 'title') {
opts = {
by: function($el) {
return $el.data('title').toLowerCase();
}
}
}
// Filter elements
$grid.shuffle('sort', opts);
});
```
The `opts` parameter can contain two properties. `reverse`, a boolean which will reverse the array. `by` is a function that is passed the element wrapped in jQuery. In the case above, we&rsquo;re returning the value of the data-date-created or data-title attributes.
Calling sort with an empty object will reset the elements to DOM order.
## Advanced Filtering
By passing a function to shuffle, you can customize the filtering to your hearts content. Shuffle will iterate over each item in the container and give your function the element wrapped in jQuery and the shuffle instance. Return `true` to keep the element or `false` to hide it.
### Example
```javascript
// Filters elements with a data-title attribute with less than 10 characters
$('#grid').shuffle(function($el, shuffle) {
return $el.data('title').length < 10;
});
```
### Searching
```javascript
// Advanced filtering
$('.filter .search').on('keyup change', function() {
var val = this.value.toLowerCase();
$('#grid').shuffle(function($el, shuffle) {
// Only search elements in the current group
if (shuffle.group !== 'all' && $.inArray(shuffle.group, $el.data('groups')) === -1) {
return false;
}
// Get the text inside our element and search for the value in the input
var text = $.trim($el.text()).toLowerCase();
return text.indexOf(val) != -1;
});
});
```
## Dependencies
* jQuery
* Modernizr
** A custom Modernizr build has been included with the plugin.
** If you already have Modernizr on your site, you may delete it.
** If you don't know what Modernizr is, leave it!
A custom Modernizr build has been included with the plugin. If you already have Modernizr on your site, you may delete it. If you don't know what Modernizr is, leave it!
## Supported Browsers
@ -120,6 +204,7 @@ _Browsers that don't support CSS transitions and transforms *cough* IE <= 9 *cou
## Changes
* 9.17.12 - Added sorting ability, made plugin responsive, added advanced filtering method. Updated to Modernizr 2.6.2
* 7.21.12 - Rewrote plugin in more object oriented structure. Added custom events. Updated to Modernizr 2.6.1.
* 7.3.12 - Removed dependency on the css file and now apply the css with javascript. Updated Modernizr to 2.5.3.

@ -1,10 +1,10 @@
// IMPORTANT!
// If you're already using Modernizr, delete it from this file. If you don't know what Modernizr is, leave it :)
/* Modernizr 2.6.1 (Custom Build) | MIT & BSD
/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-csstransforms-csstransforms3d-csstransitions-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes
*/
;window.Modernizr=function(a,b,c){function y(a){i.cssText=a}function z(a,b){return y(l.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b){for(var d in a){var e=a[d];if(!B(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function D(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}function E(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+n.join(d+" ")+d).split(" ");return A(b,"string")||A(b,"undefined")?C(e,b):(e=(a+" "+o.join(d+" ")+d).split(" "),D(e,b,c))}var d="2.6.1",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j,k={}.toString,l=" -webkit- -moz- -o- -ms- ".split(" "),m="Webkit Moz O ms",n=m.split(" "),o=m.toLowerCase().split(" "),p={},q={},r={},s=[],t=s.slice,u,v=function(a,c,d,e){var h,i,j,k=b.createElement("div"),l=b.body,m=l?l:b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),k.appendChild(j);return h=["&#173;",'<style id="s',g,'">',a,"</style>"].join(""),k.id=g,(l?k:m).innerHTML+=h,m.appendChild(k),l||(m.style.background="",f.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=t.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.csstransforms=function(){return!!E("transform")},p.csstransforms3d=function(){var a=!!E("perspective");return a&&"webkitPerspective"in f.style&&v("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},p.csstransitions=function(){return E("transition")};for(var F in p)x(p,F)&&(u=F.toLowerCase(),e[u]=p[F](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),h=j=null,e._version=d,e._prefixes=l,e._domPrefixes=o,e._cssomPrefixes=n,e.testProp=function(a){return C([a])},e.testAllProps=E,e.testStyles=v,e.prefixed=function(a,b,c){return b?E(a,b,c):E(a,"pfx")},e}(this,this.document);
;window.Modernizr=function(a,b,c){function y(a){i.cssText=a}function z(a,b){return y(l.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b){for(var d in a){var e=a[d];if(!B(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function D(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}function E(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+n.join(d+" ")+d).split(" ");return A(b,"string")||A(b,"undefined")?C(e,b):(e=(a+" "+o.join(d+" ")+d).split(" "),D(e,b,c))}var d="2.6.2",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j,k={}.toString,l=" -webkit- -moz- -o- -ms- ".split(" "),m="Webkit Moz O ms",n=m.split(" "),o=m.toLowerCase().split(" "),p={},q={},r={},s=[],t=s.slice,u,v=function(a,c,d,e){var h,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),l.appendChild(j);return h=["&#173;",'<style id="s',g,'">',a,"</style>"].join(""),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=f.style.overflow,f.style.overflow="hidden",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=t.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.csstransforms=function(){return!!E("transform")},p.csstransforms3d=function(){var a=!!E("perspective");return a&&"webkitPerspective"in f.style&&v("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},p.csstransitions=function(){return E("transition")};for(var F in p)x(p,F)&&(u=F.toLowerCase(),e[u]=p[F](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof enableClasses!="undefined"&&enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),h=j=null,e._version=d,e._prefixes=l,e._domPrefixes=o,e._cssomPrefixes=n,e.testProp=function(a){return C([a])},e.testAllProps=E,e.testStyles=v,e.prefixed=function(a,b,c){return b?E(a,b,c):E(a,"pfx")},e}(this,this.document);
/**
* jQuery Shuffle Plugin
@ -12,65 +12,104 @@
* Inspired by Isotope http://isotope.metafizzy.co/
* Use it for whatever you want!
* @author Glen Cheney (http://glencheney.com)
* @version 1.4
* @date 7/21/12
* @version 1.5
* @date 9/18/12
*/
;(function($, Modernizr) {
"use strict";
'use strict';
$.fn.sorted = function(options) {
var opts = $.extend({}, $.fn.sorted.defaults, options),
arr = this.get();
// 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(a, b) {
var valA = opts.by($(a));
var valB = opts.by($(b));
return (valA < valB) ? -1 : (valA > valB) ? 1 : 0;
});
}
if (opts.reverse) {
arr.reverse();
}
return arr;
};
$.fn.sorted.defaults = {
reverse: false,
by: null
};
var Shuffle = function($container, options) {
var self = this,
$this = $(this);
$.extend(self, {
itemWidth : 230,
marginTop : 20,
marginRight: 20,
key : 'all',
speed : 800,
easing : 'ease-out'
}, options, {
$container: $container,
supported: Modernizr.csstransforms && Modernizr.csstransitions
});
var self = this;
$.extend(self, $.fn.shuffle.options, options, $.fn.shuffle.settings);
self.$container = $container;
self.$items = self.$container.children();
self.$item = self.$items.first();
self.itemWidth = self.$item.outerWidth();
self.itemHeight = self.$item.outerHeight();
self.marginTop = parseInt(self.$item.css('marginTop'), 10);
self.marginRight = parseInt(self.$item.css('marginRight'), 10);
self.itemsPerRow = self.getItemsPerRow();
self.transitionName = self.prefixed('transition'),
self.transform = self.getPrefixed('transform');
// Get transitionend event name
var transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
};
self.transitionEndName = transEndEventNames[ self.transitionName ];
// CSS for each item
self.itemCss = {
position: 'absolute',
opacity: 1, // Everything after this is for jQuery fallback
top: 0,
left: 0,
marginTop: self.marginTop,
marginRight: self.marginRight,
'float': 'left'
opacity: 1
};
self.$items = self.$container.children();
self.itemsPerRow = Math.floor(self.$container.width() / self.itemWidth);
self.itemHeight = self.$items.first().outerHeight();
self.transitionName = self.prefixed('transition'),
self.transform = self.getPrefixed('transform');
// Set up css for transitions
self.$container.css('position', 'relative').get(0).style[self.transitionName] = 'height ' + self.speed + 'ms ' + self.easing;
self.$items.each(function(index) {
var defaults = self.itemCss;
self.$items.each(function() {
$(this).css(self.itemCss);
// Set CSS transition for transforms and opacity
if (self.supported) {
this.style[self.transitionName] = self.transform + ' ' + self.speed + 'ms ' + self.easing + ', opacity ' + self.speed + 'ms ' + self.easing;
}
// Set the margin-right to zero for the last item in the row
if ((index + 1) % self.itemsPerRow === 0) {
defaults.marginRight = 0;
}
$(this).css(self.itemCss);
// Remove margins, we don't need them anymore
this.style.marginTop = 0;
this.style.marginRight = 0;
});
// http://stackoverflow.com/questions/1852751/window-resize-event-firing-in-internet-explorer
self.windowHeight = $(window).height();
self.windowWidth = $(window).width();
$(window).on('resize.shuffle', function () {
var height = $(window).height(),
width = $(window).width();
if (width !== self.windowWidth || height !== self.windowHeight) {
self.resized();
self.windowHeight = height;
self.windowWidth = width;
}
});
// Do it
self.shuffle('all');
self.shuffle(self.group);
};
Shuffle.prototype = {
@ -81,58 +120,102 @@
* The magic. This is what makes the plugin 'shuffle'
*/
shuffle : function(category) {
var self = this,
numElements,
gridHeight;
var self = this;
if (!category) category = 'all';
if (!category) {
category = 'all';
}
// Hide/show appropriate items
if (category === 'all') {
self.$items.removeClass('concealed');
} else {
self.$items.removeClass('concealed filtered').each(function() {
var keys = $(this).attr('data-key'),
kArray = $.parseJSON(keys);
if ($.inArray(category, kArray) === -1) {
$(this).addClass('concealed');
return;
}
// Default is to show all items
self.$items.removeClass('concealed filtered');
// Loop through each item and use provided function to determine
// whether to hide it or not.
if ($.isFunction(category)) {
self.$items.each(function() {
var $item = $(this);
$item.addClass(category($item, self) ? 'filtered' : 'concealed');
});
}
// Otherwise we've been passed a category to filter by
else {
self.group = category;
if (category !== 'all') {
self.$items.each(function() {
var keys = $(this).data('groups');
if ($.inArray(category, keys) === -1) {
$(this).addClass('concealed');
return;
} else {
$(this).addClass('filtered');
}
});
}
// category === all, add filtered class to everything
else {
self.$items.addClass('filtered');
}
}
// How many filtered elements?
numElements = self.$items.not('.concealed').addClass('filtered').length;
self.visibleItems = self.$items.filter('.filtered').length;
// Shrink each concealed item
self.$container.trigger('shrink.shuffle', self);
self.fire('shrink');
self.shrink();
setTimeout(function() {
self.$container.trigger('shrunk.shuffle', self);
}, self.speed);
// Update transforms on .filtered elements so they will animate to their new positions
self.$container.trigger('filter.shuffle', self);
self.fire('filter');
self.filter();
setTimeout(function() {
self.$container.trigger('filtered.shuffle', self);
}, self.speed);
// Adjust the height of the grid
gridHeight = (Math.ceil(numElements / self.itemsPerRow) * (self.itemHeight + self.marginTop)) - self.marginTop;
self.$container.css('height', gridHeight + 'px');
// Adjust the height of the container
self.resizeContainer();
},
getItemsPerRow : function() {
var self = this,
totalWidth = self.$container.width(),
num = Math.floor(totalWidth / self.itemWidth);
// Make sure the items will fit with margins too
if (num * (self.itemWidth + self.marginRight) - self.marginRight > totalWidth) {
num -= 1;
}
return num;
},
/**
* Adjust the height of the grid
*/
resizeContainer : function() {
var self = this,
gridHeight = (Math.ceil(self.visibleItems / self.itemsPerRow) * (self.itemHeight + self.marginTop)) - self.marginTop;
self.$container.css('height', gridHeight + 'px');
},
/**
* Fire events with .shuffle namespace
*/
fire : function(name) {
this.$container.trigger(name + '.shuffle', [this]);
},
/**
* Hides the elements that don't match our filter
*/
shrink : function() {
var self = this,
$concealed = self.$container.find('.concealed');
$concealed = self.$items.filter('.concealed');
// Abort if no items
if ($concealed.length === 0) {
return;
}
self.shrinkTransitionEnded = false;
$concealed.each(function() {
var $this = $(this),
x = parseInt($this.attr('data-x'), 10),
@ -142,6 +225,7 @@
if (!y) y = 0;
self.transition({
from: 'shrink',
$this: $this,
x: x,
y: y,
@ -150,7 +234,8 @@
scale : 0.001,
opacity: 0,
height: '0px',
width: '0px'
width: '0px',
callback: self.shrinkEnd
});
});
},
@ -158,15 +243,23 @@
/**
* Loops through each item that should be shown
* Calculates the x and y position and then tranitions it
* Calculates the x and y position and then transitions it
* @param {array} 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} complete callback function
*/
filter : function() {
layout: function(items, fn) {
var self = this,
y = 0,
$filtered = self.$container.find('.filtered');
y = 0;
// Abort if no items
if (items.length === 0) {
return;
}
$filtered.each(function(index) {
var $this = $(this),
self.layoutTransitionEnded = false;
$.each(items, function(index) {
var $this = $(items[index]),
x = (index % self.itemsPerRow) * (self.itemWidth + self.marginRight),
row = Math.floor(index / self.itemsPerRow);
@ -178,6 +271,7 @@
$this.attr({'data-x' : x, 'data-y' : y});
self.transition({
from: 'layout',
$this: $this,
x: x,
y: y,
@ -186,32 +280,65 @@
scale : 1,
opacity: 1,
height: self.itemHeight + 'px',
width: self.itemWidth + 'px'
width: self.itemWidth + 'px',
callback: fn
});
});
},
/**
* Grabs the .filtered elements and passes them to layout
*/
filter : function() {
var self = this;
// If we've already sorted the elements, keep them sorted
if (self.keepSorted && self.lastSort) {
self.sort(self.lastSort, true);
} else {
var items = self.$items.filter('.filtered').get();
self.layout(items, self.filterEnd);
}
},
/**
* Gets the .filtered elements, sorts them, and passes them to layout
*
* @param {object} opts the options object for the sorted plugin
* @param {bool} [fromFilter] was called from Shuffle.filter method.
*/
sort: function(opts, fromFilter) {
var self = this,
items = self.$items.filter('.filtered').sorted(opts);
self.layout(items, function() {
if (fromFilter) {
self.filterEnd();
}
self.sortEnd();
});
self.lastSort = opts;
},
/**
* Uses Modernizr's prefixed() to get the correct vendor property name and sets it using jQuery .css()
*
* @param {jq} $el the jquery object to set the css on
* @param {string} prop the property to set (e.g. 'transition')
* @param {string} value the value of the prop
*/
setPrefixedCss : function($el, prop, value) {
$el.css(Modernizr.prefixed(prop), value);
$el.css(this.prefixed(prop), value);
},
prefixed : function(prop) {
return Modernizr.prefixed(prop);
},
/**
* Returns things like -webkit-transition or -moz-box-sizing
*
* @param {string} property to be prefixed.
* @return {string} the prefixed css property
*/
getPrefixed : function(prop) {
return Modernizr.prefixed(prop).replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
var styleName = this.prefixed(prop);
return styleName ? styleName.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-') : styleName;
},
/**
@ -227,14 +354,28 @@
* @param {float} opts.opacity opacity of the item
* @param {String} opts.height the height of the item (used when no transforms available)
* @param {String} opts.width the width of the item (used when no transforms available)
* @param {function} opts.callback complete function for the animation
*/
transition: function(opts) {
var self = this,
transform;
transform,
// Only fire callback once per collection's transition
complete = function() {
if (!self.layoutTransitionEnded && opts.from === 'layout') {
opts.callback.call(self);
self.layoutTransitionEnded = true;
} else if (!self.shrinkTransitionEnded && opts.from === 'shrink') {
opts.callback.call(self);
self.shrinkTransitionEnded = true;
}
};
// Use CSS Transforms if we have them
if (self.supported) {
if (Modernizr.csstransforms3d) {
transform = 'translate3d(' + opts.x + 'px, ' + opts.y + 'px, 0px) scale3d(' + opts.scale + ', ' + opts.scale + ', ' + opts.scale + ')';
if (self.threeD) {
transform = 'translate3d(' + opts.x + 'px, ' + opts.y + 'px, 0) scale3d(' + opts.scale + ', ' + opts.scale + ', 1)';
} else {
transform = 'translate(' + opts.x + 'px, ' + opts.y + 'px) scale(' + opts.scale + ', ' + opts.scale + ')';
}
@ -242,37 +383,82 @@
// Update css to trigger CSS Animation
opts.$this.css('opacity' , opts.opacity);
self.setPrefixedCss(opts.$this, 'transform', transform);
opts.$this.one(self.transitionEndName, complete);
} else {
// Use jQuery to animate left/top
opts.$this.animate({
opts.$this.stop().animate({
left: opts.left,
top: opts.top,
opacity: opts.opacity,
height: opts.height,
width: opts.width
}, self.speed);
}, self.speed, 'swing', complete);
}
},
/**
* On window resize, recalculate the width, height, and items per row.
*/
resized: function() {
var self = this;
self.itemWidth = self.$items.filter('.filtered').outerWidth();
self.itemHeight = self.$items.filter('.filtered').outerHeight();
self.itemsPerRow = self.getItemsPerRow();
self.filter();
self.resizeContainer();
},
shrinkEnd: function() {
this.fire('shrunk');
},
filterEnd: function() {
this.fire('filtered');
},
sortEnd: function() {
this.fire('sorted');
}
};
// Plugin definition
$.fn.shuffle = function(opts, key) {
$.fn.shuffle = function(opts, sortObj) {
return this.each(function() {
var $this = $(this),
shuffle = $this.data('shuffle');
// If we don't have a stored shuffle, make a new one and save it
if (!shuffle) {
shuffle = new Shuffle($this, opts);
$this.data('shuffle', shuffle);
}
// Execute a function
if (typeof opts === 'string') {
if (opts !== 'shuffle') {
key = opts;
}
shuffle.shuffle(key);
// If passed a string, lets decide what to do with it. Or they've provided a function to filter by
if ($.isFunction(opts) || (typeof opts === 'string' && opts !== 'sort')) {
shuffle.shuffle(opts);
// Key should be an object with propreties reversed and by.
} else if (typeof opts === 'string' && opts === 'sort') {
shuffle.sort(sortObj);
}
});
};
// Overrideable options
$.fn.shuffle.options = {
group : 'all',
speed : 800,
easing : 'ease-out',
keepSorted: true
};
// Not overrideable
$.fn.shuffle.settings = {
supported: Modernizr.csstransforms && Modernizr.csstransitions,
prefixed: Modernizr.prefixed,
threeD: Modernizr.csstransforms3d
};
})(jQuery, Modernizr);

@ -1,10 +1,10 @@
// IMPORTANT!
// If you're already using Modernizr, delete it from this file. If you don't know what Modernizr is, leave it :)
/* Modernizr 2.6.1 (Custom Build) | MIT & BSD
/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-csstransforms-csstransforms3d-csstransitions-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes
*/
;window.Modernizr=function(a,b,c){function y(a){i.cssText=a}function z(a,b){return y(l.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b){for(var d in a){var e=a[d];if(!B(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function D(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}function E(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+n.join(d+" ")+d).split(" ");return A(b,"string")||A(b,"undefined")?C(e,b):(e=(a+" "+o.join(d+" ")+d).split(" "),D(e,b,c))}var d="2.6.1",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j,k={}.toString,l=" -webkit- -moz- -o- -ms- ".split(" "),m="Webkit Moz O ms",n=m.split(" "),o=m.toLowerCase().split(" "),p={},q={},r={},s=[],t=s.slice,u,v=function(a,c,d,e){var h,i,j,k=b.createElement("div"),l=b.body,m=l?l:b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),k.appendChild(j);return h=["&#173;",'<style id="s',g,'">',a,"</style>"].join(""),k.id=g,(l?k:m).innerHTML+=h,m.appendChild(k),l||(m.style.background="",f.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=t.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.csstransforms=function(){return!!E("transform")},p.csstransforms3d=function(){var a=!!E("perspective");return a&&"webkitPerspective"in f.style&&v("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},p.csstransitions=function(){return E("transition")};for(var F in p)x(p,F)&&(u=F.toLowerCase(),e[u]=p[F](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),h=j=null,e._version=d,e._prefixes=l,e._domPrefixes=o,e._cssomPrefixes=n,e.testProp=function(a){return C([a])},e.testAllProps=E,e.testStyles=v,e.prefixed=function(a,b,c){return b?E(a,b,c):E(a,"pfx")},e}(this,this.document);
;window.Modernizr=function(a,b,c){function y(a){i.cssText=a}function z(a,b){return y(l.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b){for(var d in a){var e=a[d];if(!B(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function D(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}function E(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+n.join(d+" ")+d).split(" ");return A(b,"string")||A(b,"undefined")?C(e,b):(e=(a+" "+o.join(d+" ")+d).split(" "),D(e,b,c))}var d="2.6.2",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j,k={}.toString,l=" -webkit- -moz- -o- -ms- ".split(" "),m="Webkit Moz O ms",n=m.split(" "),o=m.toLowerCase().split(" "),p={},q={},r={},s=[],t=s.slice,u,v=function(a,c,d,e){var h,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),l.appendChild(j);return h=["&#173;",'<style id="s',g,'">',a,"</style>"].join(""),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=f.style.overflow,f.style.overflow="hidden",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=t.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.csstransforms=function(){return!!E("transform")},p.csstransforms3d=function(){var a=!!E("perspective");return a&&"webkitPerspective"in f.style&&v("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},p.csstransitions=function(){return E("transition")};for(var F in p)x(p,F)&&(u=F.toLowerCase(),e[u]=p[F](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof enableClasses!="undefined"&&enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),h=j=null,e._version=d,e._prefixes=l,e._domPrefixes=o,e._cssomPrefixes=n,e.testProp=function(a){return C([a])},e.testAllProps=E,e.testStyles=v,e.prefixed=function(a,b,c){return b?E(a,b,c):E(a,"pfx")},e}(this,this.document);
/**
* jQuery Shuffle Plugin
@ -12,13 +12,17 @@
* Inspired by Isotope http://isotope.metafizzy.co/
* Use it for whatever you want!
* @author Glen Cheney (http://glencheney.com)
* @version 1.4
* @date 7/21/12
* @version 1.5
* @date 9/18/12
*/
;(function(e,d){var g=function(a,c){var b=this;e(this);e.extend(b,{itemWidth:230,marginTop:20,marginRight:20,key:"all",speed:800,easing:"ease-out"},c,{$container:a,supported:d.csstransforms&&d.csstransitions});b.itemCss={position:"absolute",opacity:1,top:0,left:0,marginTop:b.marginTop,marginRight:b.marginRight,"float":"left"};b.$items=b.$container.children();b.itemsPerRow=Math.floor(b.$container.width()/b.itemWidth);b.itemHeight=b.$items.first().outerHeight();b.transitionName=b.prefixed("transition");
b.transform=b.getPrefixed("transform");b.$container.css("position","relative").get(0).style[b.transitionName]="height "+b.speed+"ms "+b.easing;b.$items.each(function(a){var c=b.itemCss;b.supported&&(this.style[b.transitionName]=b.transform+" "+b.speed+"ms "+b.easing+", opacity "+b.speed+"ms "+b.easing);0===(a+1)%b.itemsPerRow&&(c.marginRight=0);e(this).css(b.itemCss)});b.shuffle("all")};g.prototype={constructor:g,shuffle:function(a){var c=this,b;a||(a="all");"all"===a?c.$items.removeClass("concealed"):
c.$items.removeClass("concealed filtered").each(function(){var b=e(this).attr("data-key"),b=e.parseJSON(b);-1===e.inArray(a,b)&&e(this).addClass("concealed")});b=c.$items.not(".concealed").addClass("filtered").length;c.$container.trigger("shrink.shuffle",c);c.shrink();setTimeout(function(){c.$container.trigger("shrunk.shuffle",c)},c.speed);c.$container.trigger("filter.shuffle",c);c.filter();setTimeout(function(){c.$container.trigger("filtered.shuffle",c)},c.speed);b=Math.ceil(b/c.itemsPerRow)*(c.itemHeight+
c.marginTop)-c.marginTop;c.$container.css("height",b+"px")},shrink:function(){var a=this,c=a.$container.find(".concealed");0!==c.length&&c.each(function(){var b=e(this),c=parseInt(b.attr("data-x"),10),f=parseInt(b.attr("data-y"),10);c||(c=0);f||(f=0);a.transition({$this:b,x:c,y:f,left:c+a.itemWidth/2+"px",top:f+a.itemHeight/2+"px",scale:0.001,opacity:0,height:"0px",width:"0px"})})},filter:function(){var a=this,c=0;a.$container.find(".filtered").each(function(b){var h=e(this),f=b%a.itemsPerRow*(a.itemWidth+
a.marginRight),d=Math.floor(b/a.itemsPerRow);0===b%a.itemsPerRow&&(c=d*(a.itemHeight+a.marginTop));h.attr({"data-x":f,"data-y":c});a.transition({$this:h,x:f,y:c,left:f+"px",top:c+"px",scale:1,opacity:1,height:a.itemHeight+"px",width:a.itemWidth+"px"})})},setPrefixedCss:function(a,c,b){a.css(d.prefixed(c),b)},prefixed:function(a){return d.prefixed(a)},getPrefixed:function(a){return d.prefixed(a).replace(/([A-Z])/g,function(a,b){return"-"+b.toLowerCase()}).replace(/^ms-/,"-ms-")},transition:function(a){var c;
this.supported?(c=d.csstransforms3d?"translate3d("+a.x+"px, "+a.y+"px, 0px) scale3d("+a.scale+", "+a.scale+", "+a.scale+")":"translate("+a.x+"px, "+a.y+"px) scale("+a.scale+", "+a.scale+")",a.$this.css("opacity",a.opacity),this.setPrefixedCss(a.$this,"transform",c)):a.$this.animate({left:a.left,top:a.top,opacity:a.opacity,height:a.height,width:a.width},this.speed)}};e.fn.shuffle=function(a,c){return this.each(function(){var b=e(this),d=b.data("shuffle");d||(d=new g(b,a),b.data("shuffle",d));"string"===
typeof a&&("shuffle"!==a&&(c=a),d.shuffle(c))})}})(jQuery,Modernizr);
(function(d,g){d.fn.sorted=function(b){var c=d.extend({},d.fn.sorted.defaults,b),b=this.get();c.by!==d.noop&&(null!==c.by&&void 0!==c.by)&&b.sort(function(a,b){var e=c.by(d(a)),h=c.by(d(b));return e<h?-1:e>h?1:0});c.reverse&&b.reverse();return b};d.fn.sorted.defaults={reverse:!1,by:null};var i=function(b,c){var a=this;d.extend(a,d.fn.shuffle.options,c,d.fn.shuffle.settings);a.$container=b;a.$items=a.$container.children();a.$item=a.$items.first();a.itemWidth=a.$item.outerWidth();a.itemHeight=a.$item.outerHeight();
a.marginTop=parseInt(a.$item.css("marginTop"),10);a.marginRight=parseInt(a.$item.css("marginRight"),10);a.itemsPerRow=a.getItemsPerRow();a.transitionName=a.prefixed("transition");a.transform=a.getPrefixed("transform");a.transitionEndName={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"}[a.transitionName];a.itemCss={position:"absolute",top:0,left:0,opacity:1};a.$container.css("position","relative").get(0).style[a.transitionName]=
"height "+a.speed+"ms "+a.easing;a.$items.each(function(){d(this).css(a.itemCss);a.supported&&(this.style[a.transitionName]=a.transform+" "+a.speed+"ms "+a.easing+", opacity "+a.speed+"ms "+a.easing);this.style.marginTop=0;this.style.marginRight=0});a.windowHeight=d(window).height();a.windowWidth=d(window).width();d(window).on("resize.shuffle",function(){var b=d(window).height(),c=d(window).width();if(c!==a.windowWidth||b!==a.windowHeight)a.resized(),a.windowHeight=b,a.windowWidth=c});a.shuffle(a.group)};
i.prototype={constructor:i,shuffle:function(b){var c=this;b||(b="all");c.$items.removeClass("concealed filtered");d.isFunction(b)?c.$items.each(function(){var a=d(this);a.addClass(b(a,c)?"filtered":"concealed")}):(c.group=b,"all"!==b?c.$items.each(function(){var a=d(this).data("groups");-1===d.inArray(b,a)?d(this).addClass("concealed"):d(this).addClass("filtered")}):c.$items.addClass("filtered"));c.visibleItems=c.$items.filter(".filtered").length;c.fire("shrink");c.shrink();c.fire("filter");c.filter();
c.resizeContainer()},getItemsPerRow:function(){var b=this.$container.width(),c=Math.floor(b/this.itemWidth);c*(this.itemWidth+this.marginRight)-this.marginRight>b&&(c-=1);return c},resizeContainer:function(){var b=Math.ceil(this.visibleItems/this.itemsPerRow)*(this.itemHeight+this.marginTop)-this.marginTop;this.$container.css("height",b+"px")},fire:function(b){this.$container.trigger(b+".shuffle",[this])},shrink:function(){var b=this,c=b.$items.filter(".concealed");0!==c.length&&(b.shrinkTransitionEnded=
!1,c.each(function(){var a=d(this),c=parseInt(a.attr("data-x"),10),e=parseInt(a.attr("data-y"),10);c||(c=0);e||(e=0);b.transition({from:"shrink",$this:a,x:c,y:e,left:c+b.itemWidth/2+"px",top:e+b.itemHeight/2+"px",scale:0.001,opacity:0,height:"0px",width:"0px",callback:b.shrinkEnd})}))},layout:function(b,c){var a=this,f=0;0!==b.length&&(a.layoutTransitionEnded=!1,d.each(b,function(e){var h=d(b[e]),g=e%a.itemsPerRow*(a.itemWidth+a.marginRight),i=Math.floor(e/a.itemsPerRow);0===e%a.itemsPerRow&&(f=i*
(a.itemHeight+a.marginTop));h.attr({"data-x":g,"data-y":f});a.transition({from:"layout",$this:h,x:g,y:f,left:g+"px",top:f+"px",scale:1,opacity:1,height:a.itemHeight+"px",width:a.itemWidth+"px",callback:c})}))},filter:function(){if(this.keepSorted&&this.lastSort)this.sort(this.lastSort,!0);else{var b=this.$items.filter(".filtered").get();this.layout(b,this.filterEnd)}},sort:function(b,c){var a=this,d=a.$items.filter(".filtered").sorted(b);a.layout(d,function(){c&&a.filterEnd();a.sortEnd()});a.lastSort=
b},setPrefixedCss:function(b,c,a){b.css(this.prefixed(c),a)},getPrefixed:function(b){return(b=this.prefixed(b))?b.replace(/([A-Z])/g,function(b,a){return"-"+a.toLowerCase()}).replace(/^ms-/,"-ms-"):b},transition:function(b){var c=this,a,d=function(){!c.layoutTransitionEnded&&"layout"===b.from?(b.callback.call(c),c.layoutTransitionEnded=!0):!c.shrinkTransitionEnded&&"shrink"===b.from&&(b.callback.call(c),c.shrinkTransitionEnded=!0)};c.supported?(a=c.threeD?"translate3d("+b.x+"px, "+b.y+"px, 0) scale3d("+
b.scale+", "+b.scale+", 1)":"translate("+b.x+"px, "+b.y+"px) scale("+b.scale+", "+b.scale+")",b.$this.css("opacity",b.opacity),c.setPrefixedCss(b.$this,"transform",a),b.$this.one(c.transitionEndName,d)):b.$this.stop().animate({left:b.left,top:b.top,opacity:b.opacity,height:b.height,width:b.width},c.speed,"swing",d)},resized:function(){this.itemWidth=this.$items.filter(".filtered").outerWidth();this.itemHeight=this.$items.filter(".filtered").outerHeight();this.itemsPerRow=this.getItemsPerRow();this.filter();
this.resizeContainer()},shrinkEnd:function(){this.fire("shrunk")},filterEnd:function(){this.fire("filtered")},sortEnd:function(){this.fire("sorted")}};d.fn.shuffle=function(b,c){return this.each(function(){var a=d(this),f=a.data("shuffle");f||(f=new i(a,b),a.data("shuffle",f));d.isFunction(b)||"string"===typeof b&&"sort"!==b?f.shuffle(b):"string"===typeof b&&"sort"===b&&f.sort(c)})};d.fn.shuffle.options={group:"all",speed:800,easing:"ease-out",keepSorted:!0};d.fn.shuffle.settings={supported:g.csstransforms&&
g.csstransitions,prefixed:g.prefixed,threeD:g.csstransforms3d}})(jQuery,Modernizr);
Loading…
Cancel
Save