From 29ee0fb6c9355397d669de2ef136976ebf5c853d Mon Sep 17 00:00:00 2001 From: Glen Cheney Date: Mon, 26 Mar 2018 10:39:52 -0700 Subject: [PATCH] Rebuild with new rollup deps. --- dist/shuffle.js | 3773 +++++++++++++++++----------------- dist/shuffle.js.map | 2 +- dist/shuffle.min.js.map | 2 +- docs/dist/shuffle.js | 3773 +++++++++++++++++----------------- docs/dist/shuffle.js.map | 2 +- docs/dist/shuffle.min.js.map | 2 +- package.json | 2 +- 7 files changed, 3759 insertions(+), 3797 deletions(-) diff --git a/dist/shuffle.js b/dist/shuffle.js index ab31fdf..97f222b 100644 --- a/dist/shuffle.js +++ b/dist/shuffle.js @@ -1,2274 +1,2255 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.Shuffle = factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Shuffle = factory()); }(this, (function () { 'use strict'; -function E () { - // Keep this empty so it's easier to inherit from - // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) -} - -E.prototype = { - on: function (name, callback, ctx) { - var e = this.e || (this.e = {}); + function E () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) + } - (e[name] || (e[name] = [])).push({ - fn: callback, - ctx: ctx - }); + E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); - return this; - }, + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx + }); - once: function (name, callback, ctx) { - var self = this; - function listener () { - self.off(name, listener); - callback.apply(ctx, arguments); - } + return this; + }, - listener._ = callback; - return this.on(name, listener, ctx); - }, + once: function (name, callback, ctx) { + var self = this; + function listener () { + self.off(name, listener); + callback.apply(ctx, arguments); + } + listener._ = callback; + return this.on(name, listener, ctx); + }, - emit: function (name) { - var data = [].slice.call(arguments, 1); - var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); - var i = 0; - var len = evtArr.length; + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; - for (i; i < len; i++) { - evtArr[i].fn.apply(evtArr[i].ctx, data); - } + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } - return this; - }, + return this; + }, - off: function (name, callback) { - var e = this.e || (this.e = {}); - var evts = e[name]; - var liveEvents = []; + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; - if (evts && callback) { - for (var i = 0, len = evts.length; i < len; i++) { - if (evts[i].fn !== callback && evts[i].fn._ !== callback) - liveEvents.push(evts[i]); + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); + } } - } - // Remove event from queue to prevent memory leak - // Suggested by https://github.com/lazd - // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 - (liveEvents.length) - ? e[name] = liveEvents - : delete e[name]; - - return this; - } -}; - -var tinyEmitter = E; - -var proto = typeof Element !== 'undefined' ? Element.prototype : {}; -var vendor = proto.matches - || proto.matchesSelector - || proto.webkitMatchesSelector - || proto.mozMatchesSelector - || proto.msMatchesSelector - || proto.oMatchesSelector; - -var matchesSelector = match; - -/** - * Match `el` to `selector`. - * - * @param {Element} el - * @param {String} selector - * @return {Boolean} - * @api public - */ - -function match(el, selector) { - if (!el || el.nodeType !== 1) return false; - if (vendor) return vendor.call(el, selector); - var nodes = el.parentNode.querySelectorAll(selector); - for (var i = 0; i < nodes.length; i++) { - if (nodes[i] == el) return true; - } - return false; -} - -var throttleit = throttle; - -/** - * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds. - * - * @param {Function} func Function to wrap. - * @param {Number} wait Number of milliseconds that must elapse between `func` invocations. - * @return {Function} A new function that wraps the `func` function passed in. - */ - -function throttle (func, wait) { - var ctx, args, rtn, timeoutID; // caching - var last = 0; - - return function throttled () { - ctx = this; - args = arguments; - var delta = new Date() - last; - if (!timeoutID) - if (delta >= wait) call(); - else timeoutID = setTimeout(call, wait - delta); - return rtn; - }; + (liveEvents.length) + ? e[name] = liveEvents + : delete e[name]; - function call () { - timeoutID = 0; - last = +new Date(); - rtn = func.apply(ctx, args); - ctx = null; - args = null; - } -} - -var arrayParallel = function parallel(fns, context, callback) { - if (!callback) { - if (typeof context === 'function') { - callback = context; - context = null; - } else { - callback = noop; + return this; } - } - - var pending = fns && fns.length; - if (!pending) return callback(null, []); - - var finished = false; - var results = new Array(pending); + }; - fns.forEach(context ? function (fn, i) { - fn.call(context, maybeDone(i)); - } : function (fn, i) { - fn(maybeDone(i)); - }); + var tinyEmitter = E; - function maybeDone(i) { - return function (err, result) { - if (finished) return; + var proto = typeof Element !== 'undefined' ? Element.prototype : {}; + var vendor = proto.matches + || proto.matchesSelector + || proto.webkitMatchesSelector + || proto.mozMatchesSelector + || proto.msMatchesSelector + || proto.oMatchesSelector; - if (err) { - callback(err, results); - finished = true; - return - } + var matchesSelector = match; - results[i] = result; + /** + * Match `el` to `selector`. + * + * @param {Element} el + * @param {String} selector + * @return {Boolean} + * @api public + */ - if (!--pending) callback(null, results); - } - } -}; - -function noop() {} - -/** - * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`. - * @param {*} value Possibly numeric value. - * @return {number} `value` or zero if `value` isn't numeric. - */ -function getNumber(value) { - return parseFloat(value) || 0; -} - -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); + function match(el, selector) { + if (!el || el.nodeType !== 1) return false; + if (vendor) return vendor.call(el, selector); + var nodes = el.parentNode.querySelectorAll(selector); + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] == el) return true; } + return false; } - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - - - - - - - + var throttleit = throttle; + /** + * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds. + * + * @param {Function} func Function to wrap. + * @param {Number} wait Number of milliseconds that must elapse between `func` invocations. + * @return {Function} A new function that wraps the `func` function passed in. + */ -var inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + function throttle (func, wait) { + var ctx, args, rtn, timeoutID; // caching + var last = 0; + + return function throttled () { + ctx = this; + args = arguments; + var delta = new Date() - last; + if (!timeoutID) + if (delta >= wait) call(); + else timeoutID = setTimeout(call, wait - delta); + return rtn; + }; + + function call () { + timeoutID = 0; + last = +new Date(); + rtn = func.apply(ctx, args); + ctx = null; + args = null; + } } - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true + var arrayParallel = function parallel(fns, context, callback) { + if (!callback) { + if (typeof context === 'function') { + callback = context; + context = null; + } else { + callback = noop; + } } - }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; -}; - - - - + var pending = fns && fns.length; + if (!pending) return callback(null, []); + var finished = false; + var results = new Array(pending); + fns.forEach(context ? function (fn, i) { + fn.call(context, maybeDone(i)); + } : function (fn, i) { + fn(maybeDone(i)); + }); + function maybeDone(i) { + return function (err, result) { + if (finished) return; + if (err) { + callback(err, results); + finished = true; + return + } + results[i] = result; -var possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } + if (!--pending) callback(null, results); + } + } + }; - return call && (typeof call === "object" || typeof call === "function") ? call : self; -}; + function noop() {} -var Point = function () { /** - * Represents a coordinate pair. - * @param {number} [x=0] X. - * @param {number} [y=0] Y. + * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`. + * @param {*} value Possibly numeric value. + * @return {number} `value` or zero if `value` isn't numeric. */ - function Point(x, y) { - classCallCheck(this, Point); - - this.x = getNumber(x); - this.y = getNumber(y); + function getNumber(value) { + return parseFloat(value) || 0; } - /** - * Whether two points are equal. - * @param {Point} a Point A. - * @param {Point} b Point B. - * @return {boolean} - */ - - - createClass(Point, null, [{ - key: 'equals', - value: function equals(a, b) { - return a.x === b.x && a.y === b.y; + var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); } - }]); - return Point; -}(); - -var Rect = function () { - /** - * Class for representing rectangular regions. - * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js - * @param {number} x Left. - * @param {number} y Top. - * @param {number} w Width. - * @param {number} h Height. - * @param {number} id Identifier - * @constructor - */ - function Rect(x, y, w, h, id) { - classCallCheck(this, Rect); - - this.id = id; - - /** @type {number} */ - this.left = x; - - /** @type {number} */ - this.top = y; - - /** @type {number} */ - this.width = w; - - /** @type {number} */ - this.height = h; - } + }; - /** - * Returns whether two rectangles intersect. - * @param {Rect} a A Rectangle. - * @param {Rect} b A Rectangle. - * @return {boolean} Whether a and b intersect. - */ + var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); - createClass(Rect, null, [{ - key: "intersects", - value: function intersects(a, b) { - return a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height; + var inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } - }]); - return Rect; -}(); -var Classes = { - BASE: 'shuffle', - SHUFFLE_ITEM: 'shuffle-item', - VISIBLE: 'shuffle-item--visible', - HIDDEN: 'shuffle-item--hidden' -}; - -var id = 0; + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; -var ShuffleItem = function () { - function ShuffleItem(element) { - classCallCheck(this, ShuffleItem); + var possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } - id += 1; - this.id = id; - this.element = element; + return call && (typeof call === "object" || typeof call === "function") ? call : self; + }; + var Point = function () { /** - * Used to separate items for layout and shrink. + * Represents a coordinate pair. + * @param {number} [x=0] X. + * @param {number} [y=0] Y. */ - this.isVisible = true; + function Point(x, y) { + classCallCheck(this, Point); + + this.x = getNumber(x); + this.y = getNumber(y); + } /** - * Used to determine if a transition will happen. By the time the _layout - * and _shrink methods get the ShuffleItem instances, the `isVisible` value - * has already been changed by the separation methods, so this property is - * needed to know if the item was visible/hidden before the shrink/layout. + * Whether two points are equal. + * @param {Point} a Point A. + * @param {Point} b Point B. + * @return {boolean} */ - this.isHidden = false; - } - createClass(ShuffleItem, [{ - key: 'show', - value: function show() { - this.isVisible = true; - this.element.classList.remove(Classes.HIDDEN); - this.element.classList.add(Classes.VISIBLE); - this.element.removeAttribute('aria-hidden'); - } - }, { - key: 'hide', - value: function hide() { - this.isVisible = false; - this.element.classList.remove(Classes.VISIBLE); - this.element.classList.add(Classes.HIDDEN); - this.element.setAttribute('aria-hidden', true); - } - }, { - key: 'init', - value: function init() { - this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]); - this.applyCss(ShuffleItem.Css.INITIAL); - this.scale = ShuffleItem.Scale.VISIBLE; - this.point = new Point(); - } - }, { - key: 'addClasses', - value: function addClasses(classes) { - var _this = this; - classes.forEach(function (className) { - _this.element.classList.add(className); - }); - } - }, { - key: 'removeClasses', - value: function removeClasses(classes) { - var _this2 = this; + createClass(Point, null, [{ + key: 'equals', + value: function equals(a, b) { + return a.x === b.x && a.y === b.y; + } + }]); + return Point; + }(); - classes.forEach(function (className) { - _this2.element.classList.remove(className); - }); - } - }, { - key: 'applyCss', - value: function applyCss(obj) { - var _this3 = this; + var Rect = function () { + /** + * Class for representing rectangular regions. + * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js + * @param {number} x Left. + * @param {number} y Top. + * @param {number} w Width. + * @param {number} h Height. + * @param {number} id Identifier + * @constructor + */ + function Rect(x, y, w, h, id) { + classCallCheck(this, Rect); - Object.keys(obj).forEach(function (key) { - _this3.element.style[key] = obj[key]; - }); - } - }, { - key: 'dispose', - value: function dispose() { - this.removeClasses([Classes.HIDDEN, Classes.VISIBLE, Classes.SHUFFLE_ITEM]); + this.id = id; - this.element.removeAttribute('style'); - this.element = null; - } - }]); - return ShuffleItem; -}(); - -ShuffleItem.Css = { - INITIAL: { - position: 'absolute', - top: 0, - left: 0, - visibility: 'visible', - 'will-change': 'transform' - }, - VISIBLE: { - before: { - opacity: 1, - visibility: 'visible' - }, - after: { - transitionDelay: '' - } - }, - HIDDEN: { - before: { - opacity: 0 - }, - after: { - visibility: 'hidden', - transitionDelay: '' - } - } -}; - -ShuffleItem.Scale = { - VISIBLE: 1, - HIDDEN: 0.001 -}; - -var element = document.body || document.documentElement; -var e = document.createElement('div'); -e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; -element.appendChild(e); - -var _window$getComputedSt = window.getComputedStyle(e, null); -var width = _window$getComputedSt.width; - -var ret = width === '10px'; - -element.removeChild(e); - -/** - * Retrieve the computed style for an element, parsed as a float. - * @param {Element} element Element to get style for. - * @param {string} style Style property. - * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to - * use instead of asking for them again. - * @return {number} The parsed computed value or zero if that fails because IE - * will return 'auto' when the element doesn't have margins instead of - * the computed style. - */ -function getNumberStyle(element, style) { - var styles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window.getComputedStyle(element, null); - - var value = getNumber(styles[style]); - - // Support IE<=11 and W3C spec. - if (!ret && style === 'width') { - value += getNumber(styles.paddingLeft) + getNumber(styles.paddingRight) + getNumber(styles.borderLeftWidth) + getNumber(styles.borderRightWidth); - } else if (!ret && style === 'height') { - value += getNumber(styles.paddingTop) + getNumber(styles.paddingBottom) + getNumber(styles.borderTopWidth) + getNumber(styles.borderBottomWidth); - } + /** @type {number} */ + this.left = x; - return value; -} - -/** - * Fisher-Yates shuffle. - * http://stackoverflow.com/a/962890/373422 - * https://bost.ocks.org/mike/shuffle/ - * @param {Array} array Array to shuffle. - * @return {Array} Randomly sorted array. - */ -function randomize(array) { - var n = array.length; - - while (n) { - n -= 1; - var i = Math.floor(Math.random() * (n + 1)); - var temp = array[i]; - array[i] = array[n]; - array[n] = temp; - } + /** @type {number} */ + this.top = y; - return array; -} + /** @type {number} */ + this.width = w; -var defaults$1 = { - // Use array.reverse() to reverse the results - reverse: false, + /** @type {number} */ + this.height = h; + } - // Sorting function - by: null, + /** + * Returns whether two rectangles intersect. + * @param {Rect} a A Rectangle. + * @param {Rect} b A Rectangle. + * @return {boolean} Whether a and b intersect. + */ - // Custom sort function - compare: null, - // If true, this will skip the sorting and return a randomized order in the array - randomize: false, + createClass(Rect, null, [{ + key: "intersects", + value: function intersects(a, b) { + return a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height; + } + }]); + return Rect; + }(); + + var Classes = { + BASE: 'shuffle', + SHUFFLE_ITEM: 'shuffle-item', + VISIBLE: 'shuffle-item--visible', + HIDDEN: 'shuffle-item--hidden' + }; - // Determines which property of each item in the array is passed to the - // sorting method. - key: 'element' -}; + var id = 0; -// You can return `undefined` from the `by` function to revert to DOM order. -function sorter(arr, options) { - var opts = Object.assign({}, defaults$1, options); - var original = Array.from(arr); - var revert = false; + var ShuffleItem = function () { + function ShuffleItem(element) { + classCallCheck(this, ShuffleItem); - if (!arr.length) { - return []; - } + id += 1; + this.id = id; + this.element = element; - if (opts.randomize) { - return randomize(arr); - } + /** + * Used to separate items for layout and shrink. + */ + this.isVisible = true; - // Sort the elements by the opts.by function. - // If we don't have opts.by, default to DOM order - if (typeof opts.by === 'function') { - arr.sort(function (a, b) { - // Exit early if we already know we want to revert - if (revert) { - return 0; + /** + * Used to determine if a transition will happen. By the time the _layout + * and _shrink methods get the ShuffleItem instances, the `isVisible` value + * has already been changed by the separation methods, so this property is + * needed to know if the item was visible/hidden before the shrink/layout. + */ + this.isHidden = false; + } + + createClass(ShuffleItem, [{ + key: 'show', + value: function show() { + this.isVisible = true; + this.element.classList.remove(Classes.HIDDEN); + this.element.classList.add(Classes.VISIBLE); + this.element.removeAttribute('aria-hidden'); } - - var valA = opts.by(a[opts.key]); - var valB = opts.by(b[opts.key]); - - // If both values are undefined, use the DOM order - if (valA === undefined && valB === undefined) { - revert = true; - return 0; + }, { + key: 'hide', + value: function hide() { + this.isVisible = false; + this.element.classList.remove(Classes.VISIBLE); + this.element.classList.add(Classes.HIDDEN); + this.element.setAttribute('aria-hidden', true); } - - if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') { - return -1; + }, { + key: 'init', + value: function init() { + this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]); + this.applyCss(ShuffleItem.Css.INITIAL); + this.scale = ShuffleItem.Scale.VISIBLE; + this.point = new Point(); } + }, { + key: 'addClasses', + value: function addClasses(classes) { + var _this = this; - if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') { - return 1; + classes.forEach(function (className) { + _this.element.classList.add(className); + }); } + }, { + key: 'removeClasses', + value: function removeClasses(classes) { + var _this2 = this; - return 0; - }); - } else if (typeof opts.compare === 'function') { - arr.sort(opts.compare); - } - - // Revert to the original array if necessary - if (revert) { - return original; - } - - if (opts.reverse) { - arr.reverse(); - } - - return arr; -} - -var transitions = {}; -var eventName = 'transitionend'; -var count = 0; - -function uniqueId() { - count += 1; - return eventName + count; -} - -function cancelTransitionEnd(id) { - if (transitions[id]) { - transitions[id].element.removeEventListener(eventName, transitions[id].listener); - transitions[id] = null; - return true; - } + classes.forEach(function (className) { + _this2.element.classList.remove(className); + }); + } + }, { + key: 'applyCss', + value: function applyCss(obj) { + var _this3 = this; - return false; -} + Object.keys(obj).forEach(function (key) { + _this3.element.style[key] = obj[key]; + }); + } + }, { + key: 'dispose', + value: function dispose() { + this.removeClasses([Classes.HIDDEN, Classes.VISIBLE, Classes.SHUFFLE_ITEM]); -function onTransitionEnd(element, callback) { - var id = uniqueId(); - var listener = function listener(evt) { - if (evt.currentTarget === evt.target) { - cancelTransitionEnd(id); - callback(evt); + this.element.removeAttribute('style'); + this.element = null; + } + }]); + return ShuffleItem; + }(); + + ShuffleItem.Css = { + INITIAL: { + position: 'absolute', + top: 0, + left: 0, + visibility: 'visible', + 'will-change': 'transform' + }, + VISIBLE: { + before: { + opacity: 1, + visibility: 'visible' + }, + after: { + transitionDelay: '' + } + }, + HIDDEN: { + before: { + opacity: 0 + }, + after: { + visibility: 'hidden', + transitionDelay: '' + } } }; - element.addEventListener(eventName, listener); - - transitions[id] = { element: element, listener: listener }; - - return id; -} - -function arrayMax(array) { - return Math.max.apply(Math, array); // eslint-disable-line prefer-spread -} - -function arrayMin(array) { - return Math.min.apply(Math, array); // eslint-disable-line prefer-spread -} - -/** - * Determine the number of columns an items spans. - * @param {number} itemWidth Width of the item. - * @param {number} columnWidth Width of the column (includes gutter). - * @param {number} columns Total number of columns - * @param {number} threshold A buffer value for the size of the column to fit. - * @return {number} - */ -function getColumnSpan(itemWidth, columnWidth, columns, threshold) { - var columnSpan = itemWidth / columnWidth; - - // If the difference between the rounded column span number and the - // calculated column span number is really small, round the number to - // make it fit. - if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) { - // e.g. columnSpan = 4.0089945390298745 - columnSpan = Math.round(columnSpan); - } - - // Ensure the column span is not more than the amount of columns in the whole layout. - return Math.min(Math.ceil(columnSpan), columns); -} - -/** - * Retrieves the column set to use for placement. - * @param {number} columnSpan The number of columns this current item spans. - * @param {number} columns The total columns in the grid. - * @return {Array.} An array of numbers represeting the column set. - */ -function getAvailablePositions(positions, columnSpan, columns) { - // The item spans only one column. - if (columnSpan === 1) { - return positions; - } + ShuffleItem.Scale = { + VISIBLE: 1, + HIDDEN: 0.001 + }; - // The item spans more than one column, figure out how many different - // places it could fit horizontally. - // The group count is the number of places within the positions this block - // could fit, ignoring the current positions of items. - // Imagine a 2 column brick as the second item in a 4 column grid with - // 10px height each. Find the places it would fit: - // [20, 10, 10, 0] - // | | | - // * * * - // - // Then take the places which fit and get the bigger of the two: - // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10] - // - // Next, find the first smallest number (the short column). - // [20, 10, 10] - // | - // * - // - // And that's where it should be placed! - // - // Another example where the second column's item extends past the first: - // [10, 20, 10, 0] => [20, 20, 10] => 10 - var available = []; - - // For how many possible positions for this item there are. - for (var i = 0; i <= columns - columnSpan; i++) { - // Find the bigger value for each place it could fit. - available.push(arrayMax(positions.slice(i, i + columnSpan))); - } + var element = document.body || document.documentElement; + var e = document.createElement('div'); + e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; + element.appendChild(e); - return available; -} - -/** - * Find index of short column, the first from the left where this item will go. - * - * @param {Array.} positions The array to search for the smallest number. - * @param {number} buffer Optional buffer which is very useful when the height - * is a percentage of the width. - * @return {number} Index of the short column. - */ -function getShortColumn(positions, buffer) { - var minPosition = arrayMin(positions); - for (var i = 0, len = positions.length; i < len; i++) { - if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) { - return i; - } - } + var _window$getComputedSt = window.getComputedStyle(e, null), + width = _window$getComputedSt.width; - return 0; -} - -/** - * Determine the location of the next item, based on its size. - * @param {Object} itemSize Object with width and height. - * @param {Array.} positions Positions of the other current items. - * @param {number} gridSize The column width or row height. - * @param {number} total The total number of columns or rows. - * @param {number} threshold Buffer value for the column to fit. - * @param {number} buffer Vertical buffer for the height of items. - * @return {Point} - */ -function getItemPosition(_ref) { - var itemSize = _ref.itemSize, - positions = _ref.positions, - gridSize = _ref.gridSize, - total = _ref.total, - threshold = _ref.threshold, - buffer = _ref.buffer; - - var span = getColumnSpan(itemSize.width, gridSize, total, threshold); - var setY = getAvailablePositions(positions, span, total); - var shortColumnIndex = getShortColumn(setY, buffer); - - // Position the item - var point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]); - - // Update the columns array with the new values for each column. - // e.g. before the update the columns could be [250, 0, 0, 0] for an item - // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0]. - var setHeight = setY[shortColumnIndex] + itemSize.height; - for (var i = 0; i < span; i++) { - positions[shortColumnIndex + i] = setHeight; - } + var ret = width === '10px'; - return point; -} - -/** - * This method attempts to center items. This method could potentially be slow - * with a large number of items because it must place items, then check every - * previous item to ensure there is no overlap. - * @param {Array.} itemRects Item data objects. - * @param {number} containerWidth Width of the containing element. - * @return {Array.} - */ -function getCenteredPositions(itemRects, containerWidth) { - var rowMap = {}; - - // Populate rows by their offset because items could jump between rows like: - // a c - // bbb - itemRects.forEach(function (itemRect) { - if (rowMap[itemRect.top]) { - // Push the point to the last row array. - rowMap[itemRect.top].push(itemRect); - } else { - // Start of a new row. - rowMap[itemRect.top] = [itemRect]; - } - }); - - // For each row, find the end of the last item, then calculate - // the remaining space by dividing it by 2. Then add that - // offset to the x position of each point. - var rects = []; - var rows = []; - var centeredRows = []; - Object.keys(rowMap).forEach(function (key) { - var itemRects = rowMap[key]; - rows.push(itemRects); - var lastItem = itemRects[itemRects.length - 1]; - var end = lastItem.left + lastItem.width; - var offset = Math.round((containerWidth - end) / 2); - - var finalRects = itemRects; - var canMove = false; - if (offset > 0) { - var newRects = []; - canMove = itemRects.every(function (r) { - var newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id); - - // Check all current rects to make sure none overlap. - var noOverlap = !rects.some(function (r) { - return Rect.intersects(newRect, r); - }); + element.removeChild(e); - newRects.push(newRect); - return noOverlap; - }); - - // If none of the rectangles overlapped, the whole group can be centered. - if (canMove) { - finalRects = newRects; - } - } + /** + * Retrieve the computed style for an element, parsed as a float. + * @param {Element} element Element to get style for. + * @param {string} style Style property. + * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to + * use instead of asking for them again. + * @return {number} The parsed computed value or zero if that fails because IE + * will return 'auto' when the element doesn't have margins instead of + * the computed style. + */ + function getNumberStyle(element, style) { + var styles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window.getComputedStyle(element, null); - // If the items are not going to be offset, ensure that the original - // placement for this row will not overlap previous rows (row-spanning - // elements could be in the way). - if (!canMove) { - var intersectingRect = void 0; - var hasOverlap = itemRects.some(function (itemRect) { - return rects.some(function (r) { - var intersects = Rect.intersects(itemRect, r); - if (intersects) { - intersectingRect = r; - } - return intersects; - }); - }); + var value = getNumber(styles[style]); - // If there is any overlap, replace the overlapping row with the original. - if (hasOverlap) { - var rowIndex = centeredRows.findIndex(function (items) { - return items.includes(intersectingRect); - }); - centeredRows.splice(rowIndex, 1, rows[rowIndex]); - } + // Support IE<=11 and W3C spec. + if (!ret && style === 'width') { + value += getNumber(styles.paddingLeft) + getNumber(styles.paddingRight) + getNumber(styles.borderLeftWidth) + getNumber(styles.borderRightWidth); + } else if (!ret && style === 'height') { + value += getNumber(styles.paddingTop) + getNumber(styles.paddingBottom) + getNumber(styles.borderTopWidth) + getNumber(styles.borderBottomWidth); } - rects = rects.concat(finalRects); - centeredRows.push(finalRects); - }); - - // Reduce array of arrays to a single array of points. - // https://stackoverflow.com/a/10865042/373422 - // Then reset sort back to how the items were passed to this method. - // Remove the wrapper object with index, map to a Point. - return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread - .sort(function (a, b) { - return a.id - b.id; - }).map(function (itemRect) { - return new Point(itemRect.left, itemRect.top); - }); -} - -/** - * Hyphenates a javascript style string to a css one. For example: - * MozBoxSizing -> -moz-box-sizing. - * @param {string} str The string to hyphenate. - * @return {string} The hyphenated string. - */ -function hyphenate(str) { - return str.replace(/([A-Z])/g, function (str, m1) { - return "-" + m1.toLowerCase(); - }); -} - -function arrayUnique(x) { - return Array.from(new Set(x)); -} - -// Used for unique instance variables -var id$1 = 0; - -var Shuffle = function (_TinyEmitter) { - inherits(Shuffle, _TinyEmitter); + return value; + } /** - * Categorize, sort, and filter a responsive grid of items. - * - * @param {Element} element An element which is the parent container for the grid items. - * @param {Object} [options=Shuffle.options] Options object. - * @constructor + * Fisher-Yates shuffle. + * http://stackoverflow.com/a/962890/373422 + * https://bost.ocks.org/mike/shuffle/ + * @param {Array} array Array to shuffle. + * @return {Array} Randomly sorted array. */ - function Shuffle(element) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - classCallCheck(this, Shuffle); - - var _this = possibleConstructorReturn(this, (Shuffle.__proto__ || Object.getPrototypeOf(Shuffle)).call(this)); + function randomize(array) { + var n = array.length; - _this.options = Object.assign({}, Shuffle.options, options); - - // Allow misspelling of delimiter since that's how it used to be. - // Remove in v6. - if (_this.options.delimeter) { - _this.options.delimiter = _this.options.delimeter; + while (n) { + n -= 1; + var i = Math.floor(Math.random() * (n + 1)); + var temp = array[i]; + array[i] = array[n]; + array[n] = temp; } - _this.lastSort = {}; - _this.group = Shuffle.ALL_ITEMS; - _this.lastFilter = Shuffle.ALL_ITEMS; - _this.isEnabled = true; - _this.isDestroyed = false; - _this.isInitialized = false; - _this._transitions = []; - _this.isTransitioning = false; - _this._queue = []; + return array; + } - var el = _this._getElementOption(element); + var defaults$1 = { + // Use array.reverse() to reverse the results + reverse: false, - if (!el) { - throw new TypeError('Shuffle needs to be initialized with an element.'); - } + // Sorting function + by: null, - _this.element = el; - _this.id = 'shuffle_' + id$1; - id$1 += 1; - - _this._init(); - _this.isInitialized = true; - return _this; - } + // Custom sort function + compare: null, - createClass(Shuffle, [{ - key: '_init', - value: function _init() { - this.items = this._getItems(); + // If true, this will skip the sorting and return a randomized order in the array + randomize: false, - this.options.sizer = this._getElementOption(this.options.sizer); + // Determines which property of each item in the array is passed to the + // sorting method. + key: 'element' + }; - // Add class and invalidate styles - this.element.classList.add(Shuffle.Classes.BASE); + // You can return `undefined` from the `by` function to revert to DOM order. + function sorter(arr, options) { + var opts = Object.assign({}, defaults$1, options); + var original = Array.from(arr); + var revert = false; - // Set initial css for each item - this._initItems(this.items); + if (!arr.length) { + return []; + } - // Bind resize events - this._onResize = this._getResizeFunction(); - window.addEventListener('resize', this._onResize); + if (opts.randomize) { + return randomize(arr); + } - // If the page has not already emitted the `load` event, call layout on load. - // This avoids layout issues caused by images and fonts loading after the - // instance has been initialized. - if (document.readyState !== 'complete') { - var layout = this.layout.bind(this); - window.addEventListener('load', function onLoad() { - window.removeEventListener('load', onLoad); - layout(); - }); - } + // Sort the elements by the opts.by function. + // If we don't have opts.by, default to DOM order + if (typeof opts.by === 'function') { + arr.sort(function (a, b) { + // Exit early if we already know we want to revert + if (revert) { + return 0; + } - // Get container css all in one request. Causes reflow - var containerCss = window.getComputedStyle(this.element, null); - var containerWidth = Shuffle.getSize(this.element).width; + var valA = opts.by(a[opts.key]); + var valB = opts.by(b[opts.key]); - // Add styles to the container if it doesn't have them. - this._validateStyles(containerCss); + // If both values are undefined, use the DOM order + if (valA === undefined && valB === undefined) { + revert = true; + return 0; + } - // We already got the container's width above, no need to cause another - // reflow getting it again... Calculate the number of columns there will be - this._setColumns(containerWidth); + if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') { + return -1; + } - // Kick off! - this.filter(this.options.group, this.options.initialSort); + if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') { + return 1; + } - // The shuffle items haven't had transitions set on them yet so the user - // doesn't see the first layout. Set them now that the first layout is done. - // First, however, a synchronous layout must be caused for the previous - // styles to be applied without transitions. - this.element.offsetWidth; // eslint-disable-line no-unused-expressions - this.setItemTransitions(this.items); - this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing; + return 0; + }); + } else if (typeof opts.compare === 'function') { + arr.sort(opts.compare); } - /** - * Returns a throttled and proxied function for the resize handler. - * @return {function} - * @private - */ - - }, { - key: '_getResizeFunction', - value: function _getResizeFunction() { - var resizeFunction = this._handleResize.bind(this); - return this.options.throttle ? this.options.throttle(resizeFunction, this.options.throttleTime) : resizeFunction; + // Revert to the original array if necessary + if (revert) { + return original; } - /** - * Retrieve an element from an option. - * @param {string|jQuery|Element} option The option to check. - * @return {?Element} The plain element or null. - * @private - */ + if (opts.reverse) { + arr.reverse(); + } - }, { - key: '_getElementOption', - value: function _getElementOption(option) { - // If column width is a string, treat is as a selector and search for the - // sizer element within the outermost container - if (typeof option === 'string') { - return this.element.querySelector(option); + return arr; + } - // Check for an element - } else if (option && option.nodeType && option.nodeType === 1) { - return option; + var transitions = {}; + var eventName = 'transitionend'; + var count = 0; - // Check for jQuery object - } else if (option && option.jquery) { - return option[0]; - } + function uniqueId() { + count += 1; + return eventName + count; + } - return null; + function cancelTransitionEnd(id) { + if (transitions[id]) { + transitions[id].element.removeEventListener(eventName, transitions[id].listener); + transitions[id] = null; + return true; } - /** - * Ensures the shuffle container has the css styles it needs applied to it. - * @param {Object} styles Key value pairs for position and overflow. - * @private - */ + return false; + } - }, { - key: '_validateStyles', - value: function _validateStyles(styles) { - // Position cannot be static. - if (styles.position === 'static') { - this.element.style.position = 'relative'; + function onTransitionEnd(element, callback) { + var id = uniqueId(); + var listener = function listener(evt) { + if (evt.currentTarget === evt.target) { + cancelTransitionEnd(id); + callback(evt); } + }; - // Overflow has to be hidden. - if (styles.overflow !== 'hidden') { - this.element.style.overflow = 'hidden'; - } - } + element.addEventListener(eventName, listener); - /** - * Filter the elements by a category. - * @param {string|string[]|function(Element):boolean} [category] Category to - * filter by. If it's given, the last category will be used to filter the items. - * @param {Array} [collection] Optionally filter a collection. Defaults to - * all the items. - * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} - * @private - */ + transitions[id] = { element: element, listener: listener }; - }, { - key: '_filter', - value: function _filter() { - var category = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastFilter; - var collection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.items; - - var set$$1 = this._getFilteredSets(category, collection); + return id; + } - // Individually add/remove hidden/visible classes - this._toggleFilterClasses(set$$1); + function arrayMax(array) { + return Math.max.apply(Math, array); // eslint-disable-line prefer-spread + } - // Save the last filter in case elements are appended. - this.lastFilter = category; + function arrayMin(array) { + return Math.min.apply(Math, array); // eslint-disable-line prefer-spread + } - // This is saved mainly because providing a filter function (like searching) - // will overwrite the `lastFilter` property every time its called. - if (typeof category === 'string') { - this.group = category; - } + /** + * Determine the number of columns an items spans. + * @param {number} itemWidth Width of the item. + * @param {number} columnWidth Width of the column (includes gutter). + * @param {number} columns Total number of columns + * @param {number} threshold A buffer value for the size of the column to fit. + * @return {number} + */ + function getColumnSpan(itemWidth, columnWidth, columns, threshold) { + var columnSpan = itemWidth / columnWidth; - return set$$1; + // If the difference between the rounded column span number and the + // calculated column span number is really small, round the number to + // make it fit. + if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) { + // e.g. columnSpan = 4.0089945390298745 + columnSpan = Math.round(columnSpan); } - /** - * Returns an object containing the visible and hidden elements. - * @param {string|string[]|function(Element):boolean} category Category or function to filter by. - * @param {ShuffleItem[]} items A collection of items to filter. - * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} - * @private - */ + // Ensure the column span is not more than the amount of columns in the whole layout. + return Math.min(Math.ceil(columnSpan), columns); + } - }, { - key: '_getFilteredSets', - value: function _getFilteredSets(category, items) { - var _this2 = this; + /** + * Retrieves the column set to use for placement. + * @param {number} columnSpan The number of columns this current item spans. + * @param {number} columns The total columns in the grid. + * @return {Array.} An array of numbers represeting the column set. + */ + function getAvailablePositions(positions, columnSpan, columns) { + // The item spans only one column. + if (columnSpan === 1) { + return positions; + } + + // The item spans more than one column, figure out how many different + // places it could fit horizontally. + // The group count is the number of places within the positions this block + // could fit, ignoring the current positions of items. + // Imagine a 2 column brick as the second item in a 4 column grid with + // 10px height each. Find the places it would fit: + // [20, 10, 10, 0] + // | | | + // * * * + // + // Then take the places which fit and get the bigger of the two: + // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10] + // + // Next, find the first smallest number (the short column). + // [20, 10, 10] + // | + // * + // + // And that's where it should be placed! + // + // Another example where the second column's item extends past the first: + // [10, 20, 10, 0] => [20, 20, 10] => 10 + var available = []; + + // For how many possible positions for this item there are. + for (var i = 0; i <= columns - columnSpan; i++) { + // Find the bigger value for each place it could fit. + available.push(arrayMax(positions.slice(i, i + columnSpan))); + } + + return available; + } - var visible = []; - var hidden = []; + /** + * Find index of short column, the first from the left where this item will go. + * + * @param {Array.} positions The array to search for the smallest number. + * @param {number} buffer Optional buffer which is very useful when the height + * is a percentage of the width. + * @return {number} Index of the short column. + */ + function getShortColumn(positions, buffer) { + var minPosition = arrayMin(positions); + for (var i = 0, len = positions.length; i < len; i++) { + if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) { + return i; + } + } - // category === 'all', add visible class to everything - if (category === Shuffle.ALL_ITEMS) { - visible = items; + return 0; + } - // Loop through each item and use provided function to determine - // whether to hide it or not. + /** + * Determine the location of the next item, based on its size. + * @param {Object} itemSize Object with width and height. + * @param {Array.} positions Positions of the other current items. + * @param {number} gridSize The column width or row height. + * @param {number} total The total number of columns or rows. + * @param {number} threshold Buffer value for the column to fit. + * @param {number} buffer Vertical buffer for the height of items. + * @return {Point} + */ + function getItemPosition(_ref) { + var itemSize = _ref.itemSize, + positions = _ref.positions, + gridSize = _ref.gridSize, + total = _ref.total, + threshold = _ref.threshold, + buffer = _ref.buffer; + + var span = getColumnSpan(itemSize.width, gridSize, total, threshold); + var setY = getAvailablePositions(positions, span, total); + var shortColumnIndex = getShortColumn(setY, buffer); + + // Position the item + var point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]); + + // Update the columns array with the new values for each column. + // e.g. before the update the columns could be [250, 0, 0, 0] for an item + // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0]. + var setHeight = setY[shortColumnIndex] + itemSize.height; + for (var i = 0; i < span; i++) { + positions[shortColumnIndex + i] = setHeight; + } + + return point; + } + + /** + * This method attempts to center items. This method could potentially be slow + * with a large number of items because it must place items, then check every + * previous item to ensure there is no overlap. + * @param {Array.} itemRects Item data objects. + * @param {number} containerWidth Width of the containing element. + * @return {Array.} + */ + function getCenteredPositions(itemRects, containerWidth) { + var rowMap = {}; + + // Populate rows by their offset because items could jump between rows like: + // a c + // bbb + itemRects.forEach(function (itemRect) { + if (rowMap[itemRect.top]) { + // Push the point to the last row array. + rowMap[itemRect.top].push(itemRect); } else { - items.forEach(function (item) { - if (_this2._doesPassFilter(category, item.element)) { - visible.push(item); - } else { - hidden.push(item); - } - }); + // Start of a new row. + rowMap[itemRect.top] = [itemRect]; } + }); - return { - visible: visible, - hidden: hidden - }; - } + // For each row, find the end of the last item, then calculate + // the remaining space by dividing it by 2. Then add that + // offset to the x position of each point. + var rects = []; + var rows = []; + var centeredRows = []; + Object.keys(rowMap).forEach(function (key) { + var itemRects = rowMap[key]; + rows.push(itemRects); + var lastItem = itemRects[itemRects.length - 1]; + var end = lastItem.left + lastItem.width; + var offset = Math.round((containerWidth - end) / 2); + + var finalRects = itemRects; + var canMove = false; + if (offset > 0) { + var newRects = []; + canMove = itemRects.every(function (r) { + var newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id); + + // Check all current rects to make sure none overlap. + var noOverlap = !rects.some(function (r) { + return Rect.intersects(newRect, r); + }); - /** - * Test an item to see if it passes a category. - * @param {string|string[]|function():boolean} category Category or function to filter by. - * @param {Element} element An element to test. - * @return {boolean} Whether it passes the category/filter. - * @private - */ + newRects.push(newRect); + return noOverlap; + }); - }, { - key: '_doesPassFilter', - value: function _doesPassFilter(category, element) { - if (typeof category === 'function') { - return category.call(element, element, this); + // If none of the rectangles overlapped, the whole group can be centered. + if (canMove) { + finalRects = newRects; + } } - // Check each element's data-groups attribute against the given category. - var attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY); - var keys = this.options.delimiter ? attr.split(this.options.delimiter) : JSON.parse(attr); - - function testCategory(category) { - return keys.includes(category); - } + // If the items are not going to be offset, ensure that the original + // placement for this row will not overlap previous rows (row-spanning + // elements could be in the way). + if (!canMove) { + var intersectingRect = void 0; + var hasOverlap = itemRects.some(function (itemRect) { + return rects.some(function (r) { + var intersects = Rect.intersects(itemRect, r); + if (intersects) { + intersectingRect = r; + } + return intersects; + }); + }); - if (Array.isArray(category)) { - if (this.options.filterMode === Shuffle.FilterMode.ANY) { - return category.some(testCategory); + // If there is any overlap, replace the overlapping row with the original. + if (hasOverlap) { + var rowIndex = centeredRows.findIndex(function (items) { + return items.includes(intersectingRect); + }); + centeredRows.splice(rowIndex, 1, rows[rowIndex]); } - return category.every(testCategory); } - return keys.includes(category); - } - - /** - * Toggles the visible and hidden class names. - * @param {{visible, hidden}} Object with visible and hidden arrays. - * @private - */ + rects = rects.concat(finalRects); + centeredRows.push(finalRects); + }); - }, { - key: '_toggleFilterClasses', - value: function _toggleFilterClasses(_ref) { - var visible = _ref.visible, - hidden = _ref.hidden; + // Reduce array of arrays to a single array of points. + // https://stackoverflow.com/a/10865042/373422 + // Then reset sort back to how the items were passed to this method. + // Remove the wrapper object with index, map to a Point. + return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread + .sort(function (a, b) { + return a.id - b.id; + }).map(function (itemRect) { + return new Point(itemRect.left, itemRect.top); + }); + } - visible.forEach(function (item) { - item.show(); - }); + /** + * Hyphenates a javascript style string to a css one. For example: + * MozBoxSizing -> -moz-box-sizing. + * @param {string} str The string to hyphenate. + * @return {string} The hyphenated string. + */ + function hyphenate(str) { + return str.replace(/([A-Z])/g, function (str, m1) { + return "-" + m1.toLowerCase(); + }); + } - hidden.forEach(function (item) { - item.hide(); - }); - } + function arrayUnique(x) { + return Array.from(new Set(x)); + } - /** - * Set the initial css for each item - * @param {ShuffleItem[]} items Set to initialize. - * @private - */ + // Used for unique instance variables + var id$1 = 0; - }, { - key: '_initItems', - value: function _initItems(items) { - items.forEach(function (item) { - item.init(); - }); - } + var Shuffle = function (_TinyEmitter) { + inherits(Shuffle, _TinyEmitter); /** - * Remove element reference and styles. - * @param {ShuffleItem[]} items Set to dispose. - * @private + * Categorize, sort, and filter a responsive grid of items. + * + * @param {Element} element An element which is the parent container for the grid items. + * @param {Object} [options=Shuffle.options] Options object. + * @constructor */ + function Shuffle(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, Shuffle); - }, { - key: '_disposeItems', - value: function _disposeItems(items) { - items.forEach(function (item) { - item.dispose(); - }); - } + var _this = possibleConstructorReturn(this, (Shuffle.__proto__ || Object.getPrototypeOf(Shuffle)).call(this)); - /** - * Updates the visible item count. - * @private - */ + _this.options = Object.assign({}, Shuffle.options, options); - }, { - key: '_updateItemCount', - value: function _updateItemCount() { - this.visibleItems = this._getFilteredItems().length; - } + // Allow misspelling of delimiter since that's how it used to be. + // Remove in v6. + if (_this.options.delimeter) { + _this.options.delimiter = _this.options.delimeter; + } - /** - * Sets css transform transition on a group of elements. This is not executed - * at the same time as `item.init` so that transitions don't occur upon - * initialization of a new Shuffle instance. - * @param {ShuffleItem[]} items Shuffle items to set transitions on. - * @protected - */ + _this.lastSort = {}; + _this.group = Shuffle.ALL_ITEMS; + _this.lastFilter = Shuffle.ALL_ITEMS; + _this.isEnabled = true; + _this.isDestroyed = false; + _this.isInitialized = false; + _this._transitions = []; + _this.isTransitioning = false; + _this._queue = []; - }, { - key: 'setItemTransitions', - value: function setItemTransitions(items) { - var _options = this.options, - speed = _options.speed, - easing = _options.easing; + var el = _this._getElementOption(element); - var positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left']; + if (!el) { + throw new TypeError('Shuffle needs to be initialized with an element.'); + } - // Allow users to transtion other properties if they exist in the `before` - // css mapping of the shuffle item. - var cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(function (k) { - return hyphenate(k); - }); - var properties = positionProps.concat(cssProps).join(); + _this.element = el; + _this.id = 'shuffle_' + id$1; + id$1 += 1; - items.forEach(function (item) { - item.element.style.transitionDuration = speed + 'ms'; - item.element.style.transitionTimingFunction = easing; - item.element.style.transitionProperty = properties; - }); - } - }, { - key: '_getItems', - value: function _getItems() { - var _this3 = this; - - return Array.from(this.element.children).filter(function (el) { - return matchesSelector(el, _this3.options.itemSelector); - }).map(function (el) { - return new ShuffleItem(el); - }); + _this._init(); + _this.isInitialized = true; + return _this; } - /** - * Combine the current items array with a new one and sort it by DOM order. - * @param {ShuffleItem[]} items Items to track. - * @return {ShuffleItem[]} - */ + createClass(Shuffle, [{ + key: '_init', + value: function _init() { + this.items = this._getItems(); - }, { - key: '_mergeNewItems', - value: function _mergeNewItems(items) { - var children = Array.from(this.element.children); - return sorter(this.items.concat(items), { - by: function by(element) { - return children.indexOf(element); - } - }); - } - }, { - key: '_getFilteredItems', - value: function _getFilteredItems() { - return this.items.filter(function (item) { - return item.isVisible; - }); - } - }, { - key: '_getConcealedItems', - value: function _getConcealedItems() { - return this.items.filter(function (item) { - return !item.isVisible; - }); - } + this.options.sizer = this._getElementOption(this.options.sizer); - /** - * Returns the column size, based on column width and sizer options. - * @param {number} containerWidth Size of the parent container. - * @param {number} gutterSize Size of the gutters. - * @return {number} - * @private - */ + // Add class and invalidate styles + this.element.classList.add(Shuffle.Classes.BASE); - }, { - key: '_getColumnSize', - value: function _getColumnSize(containerWidth, gutterSize) { - var size = void 0; + // Set initial css for each item + this._initItems(this.items); - // If the columnWidth property is a function, then the grid is fluid - if (typeof this.options.columnWidth === 'function') { - size = this.options.columnWidth(containerWidth); + // Bind resize events + this._onResize = this._getResizeFunction(); + window.addEventListener('resize', this._onResize); - // columnWidth option isn't a function, are they using a sizing element? - } else if (this.options.sizer) { - size = Shuffle.getSize(this.options.sizer).width; + // If the page has not already emitted the `load` event, call layout on load. + // This avoids layout issues caused by images and fonts loading after the + // instance has been initialized. + if (document.readyState !== 'complete') { + var layout = this.layout.bind(this); + window.addEventListener('load', function onLoad() { + window.removeEventListener('load', onLoad); + layout(); + }); + } - // if not, how about the explicitly set option? - } else if (this.options.columnWidth) { - size = this.options.columnWidth; + // Get container css all in one request. Causes reflow + var containerCss = window.getComputedStyle(this.element, null); + var containerWidth = Shuffle.getSize(this.element).width; - // or use the size of the first item - } else if (this.items.length > 0) { - size = Shuffle.getSize(this.items[0].element, true).width; + // Add styles to the container if it doesn't have them. + this._validateStyles(containerCss); - // if there's no items, use size of container - } else { - size = containerWidth; - } + // We already got the container's width above, no need to cause another + // reflow getting it again... Calculate the number of columns there will be + this._setColumns(containerWidth); + + // Kick off! + this.filter(this.options.group, this.options.initialSort); - // Don't let them set a column width of zero. - if (size === 0) { - size = containerWidth; + // The shuffle items haven't had transitions set on them yet so the user + // doesn't see the first layout. Set them now that the first layout is done. + // First, however, a synchronous layout must be caused for the previous + // styles to be applied without transitions. + this.element.offsetWidth; // eslint-disable-line no-unused-expressions + this.setItemTransitions(this.items); + this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing; } - return size + gutterSize; - } + /** + * Returns a throttled and proxied function for the resize handler. + * @return {function} + * @private + */ + + }, { + key: '_getResizeFunction', + value: function _getResizeFunction() { + var resizeFunction = this._handleResize.bind(this); + return this.options.throttle ? this.options.throttle(resizeFunction, this.options.throttleTime) : resizeFunction; + } - /** - * Returns the gutter size, based on gutter width and sizer options. - * @param {number} containerWidth Size of the parent container. - * @return {number} - * @private - */ + /** + * Retrieve an element from an option. + * @param {string|jQuery|Element} option The option to check. + * @return {?Element} The plain element or null. + * @private + */ + + }, { + key: '_getElementOption', + value: function _getElementOption(option) { + // If column width is a string, treat is as a selector and search for the + // sizer element within the outermost container + if (typeof option === 'string') { + return this.element.querySelector(option); + + // Check for an element + } else if (option && option.nodeType && option.nodeType === 1) { + return option; + + // Check for jQuery object + } else if (option && option.jquery) { + return option[0]; + } - }, { - key: '_getGutterSize', - value: function _getGutterSize(containerWidth) { - var size = void 0; - if (typeof this.options.gutterWidth === 'function') { - size = this.options.gutterWidth(containerWidth); - } else if (this.options.sizer) { - size = getNumberStyle(this.options.sizer, 'marginLeft'); - } else { - size = this.options.gutterWidth; + return null; } - return size; - } + /** + * Ensures the shuffle container has the css styles it needs applied to it. + * @param {Object} styles Key value pairs for position and overflow. + * @private + */ + + }, { + key: '_validateStyles', + value: function _validateStyles(styles) { + // Position cannot be static. + if (styles.position === 'static') { + this.element.style.position = 'relative'; + } - /** - * Calculate the number of columns to be used. Gets css if using sizer element. - * @param {number} [containerWidth] Optionally specify a container width if - * it's already available. - */ + // Overflow has to be hidden. + if (styles.overflow !== 'hidden') { + this.element.style.overflow = 'hidden'; + } + } + + /** + * Filter the elements by a category. + * @param {string|string[]|function(Element):boolean} [category] Category to + * filter by. If it's given, the last category will be used to filter the items. + * @param {Array} [collection] Optionally filter a collection. Defaults to + * all the items. + * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} + * @private + */ + + }, { + key: '_filter', + value: function _filter() { + var category = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastFilter; + var collection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.items; + + var set$$1 = this._getFilteredSets(category, collection); + + // Individually add/remove hidden/visible classes + this._toggleFilterClasses(set$$1); + + // Save the last filter in case elements are appended. + this.lastFilter = category; + + // This is saved mainly because providing a filter function (like searching) + // will overwrite the `lastFilter` property every time its called. + if (typeof category === 'string') { + this.group = category; + } - }, { - key: '_setColumns', - value: function _setColumns() { - var containerWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Shuffle.getSize(this.element).width; + return set$$1; + } - var gutter = this._getGutterSize(containerWidth); - var columnWidth = this._getColumnSize(containerWidth, gutter); - var calculatedColumns = (containerWidth + gutter) / columnWidth; + /** + * Returns an object containing the visible and hidden elements. + * @param {string|string[]|function(Element):boolean} category Category or function to filter by. + * @param {ShuffleItem[]} items A collection of items to filter. + * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} + * @private + */ + + }, { + key: '_getFilteredSets', + value: function _getFilteredSets(category, items) { + var _this2 = this; + + var visible = []; + var hidden = []; + + // category === 'all', add visible class to everything + if (category === Shuffle.ALL_ITEMS) { + visible = items; + + // Loop through each item and use provided function to determine + // whether to hide it or not. + } else { + items.forEach(function (item) { + if (_this2._doesPassFilter(category, item.element)) { + visible.push(item); + } else { + hidden.push(item); + } + }); + } - // Widths given from getStyles are not precise enough... - if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) < this.options.columnThreshold) { - // e.g. calculatedColumns = 11.998876 - calculatedColumns = Math.round(calculatedColumns); + return { + visible: visible, + hidden: hidden + }; } - this.cols = Math.max(Math.floor(calculatedColumns), 1); - this.containerWidth = containerWidth; - this.colWidth = columnWidth; - } + /** + * Test an item to see if it passes a category. + * @param {string|string[]|function():boolean} category Category or function to filter by. + * @param {Element} element An element to test. + * @return {boolean} Whether it passes the category/filter. + * @private + */ + + }, { + key: '_doesPassFilter', + value: function _doesPassFilter(category, element) { + if (typeof category === 'function') { + return category.call(element, element, this); + } - /** - * Adjust the height of the grid - */ + // Check each element's data-groups attribute against the given category. + var attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY); + var keys = this.options.delimiter ? attr.split(this.options.delimiter) : JSON.parse(attr); - }, { - key: '_setContainerSize', - value: function _setContainerSize() { - this.element.style.height = this._getContainerSize() + 'px'; - } + function testCategory(category) { + return keys.includes(category); + } + + if (Array.isArray(category)) { + if (this.options.filterMode === Shuffle.FilterMode.ANY) { + return category.some(testCategory); + } + return category.every(testCategory); + } - /** - * Based on the column heights, it returns the biggest one. - * @return {number} - * @private - */ + return keys.includes(category); + } - }, { - key: '_getContainerSize', - value: function _getContainerSize() { - return arrayMax(this.positions); - } + /** + * Toggles the visible and hidden class names. + * @param {{visible, hidden}} Object with visible and hidden arrays. + * @private + */ - /** - * Get the clamped stagger amount. - * @param {number} index Index of the item to be staggered. - * @return {number} - */ + }, { + key: '_toggleFilterClasses', + value: function _toggleFilterClasses(_ref) { + var visible = _ref.visible, + hidden = _ref.hidden; - }, { - key: '_getStaggerAmount', - value: function _getStaggerAmount(index) { - return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax); - } + visible.forEach(function (item) { + item.show(); + }); - /** - * Emit an event from this instance. - * @param {string} name Event name. - * @param {Object} [data={}] Optional object data. - */ + hidden.forEach(function (item) { + item.hide(); + }); + } - }, { - key: '_dispatch', - value: function _dispatch(name) { - var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + /** + * Set the initial css for each item + * @param {ShuffleItem[]} items Set to initialize. + * @private + */ - if (this.isDestroyed) { - return; + }, { + key: '_initItems', + value: function _initItems(items) { + items.forEach(function (item) { + item.init(); + }); } - data.shuffle = this; - this.emit(name, data); - } + /** + * Remove element reference and styles. + * @param {ShuffleItem[]} items Set to dispose. + * @private + */ - /** - * Zeros out the y columns array, which is used to determine item placement. - * @private - */ + }, { + key: '_disposeItems', + value: function _disposeItems(items) { + items.forEach(function (item) { + item.dispose(); + }); + } + + /** + * Updates the visible item count. + * @private + */ - }, { - key: '_resetCols', - value: function _resetCols() { - var i = this.cols; - this.positions = []; - while (i) { - i -= 1; - this.positions.push(0); + }, { + key: '_updateItemCount', + value: function _updateItemCount() { + this.visibleItems = this._getFilteredItems().length; } - } - /** - * Loops through each item that should be shown and calculates the x, y position. - * @param {ShuffleItem[]} items Array of items that will be shown/layed - * out in order in their array. - */ + /** + * Sets css transform transition on a group of elements. This is not executed + * at the same time as `item.init` so that transitions don't occur upon + * initialization of a new Shuffle instance. + * @param {ShuffleItem[]} items Shuffle items to set transitions on. + * @protected + */ + + }, { + key: 'setItemTransitions', + value: function setItemTransitions(items) { + var _options = this.options, + speed = _options.speed, + easing = _options.easing; + + var positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left']; + + // Allow users to transtion other properties if they exist in the `before` + // css mapping of the shuffle item. + var cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(function (k) { + return hyphenate(k); + }); + var properties = positionProps.concat(cssProps).join(); - }, { - key: '_layout', - value: function _layout(items) { - var _this4 = this; + items.forEach(function (item) { + item.element.style.transitionDuration = speed + 'ms'; + item.element.style.transitionTimingFunction = easing; + item.element.style.transitionProperty = properties; + }); + } + }, { + key: '_getItems', + value: function _getItems() { + var _this3 = this; + + return Array.from(this.element.children).filter(function (el) { + return matchesSelector(el, _this3.options.itemSelector); + }).map(function (el) { + return new ShuffleItem(el); + }); + } - var itemPositions = this._getNextPositions(items); + /** + * Combine the current items array with a new one and sort it by DOM order. + * @param {ShuffleItem[]} items Items to track. + * @return {ShuffleItem[]} + */ + + }, { + key: '_mergeNewItems', + value: function _mergeNewItems(items) { + var children = Array.from(this.element.children); + return sorter(this.items.concat(items), { + by: function by(element) { + return children.indexOf(element); + } + }); + } + }, { + key: '_getFilteredItems', + value: function _getFilteredItems() { + return this.items.filter(function (item) { + return item.isVisible; + }); + } + }, { + key: '_getConcealedItems', + value: function _getConcealedItems() { + return this.items.filter(function (item) { + return !item.isVisible; + }); + } - var count = 0; - items.forEach(function (item, i) { - function callback() { - item.applyCss(ShuffleItem.Css.VISIBLE.after); + /** + * Returns the column size, based on column width and sizer options. + * @param {number} containerWidth Size of the parent container. + * @param {number} gutterSize Size of the gutters. + * @return {number} + * @private + */ + + }, { + key: '_getColumnSize', + value: function _getColumnSize(containerWidth, gutterSize) { + var size = void 0; + + // If the columnWidth property is a function, then the grid is fluid + if (typeof this.options.columnWidth === 'function') { + size = this.options.columnWidth(containerWidth); + + // columnWidth option isn't a function, are they using a sizing element? + } else if (this.options.sizer) { + size = Shuffle.getSize(this.options.sizer).width; + + // if not, how about the explicitly set option? + } else if (this.options.columnWidth) { + size = this.options.columnWidth; + + // or use the size of the first item + } else if (this.items.length > 0) { + size = Shuffle.getSize(this.items[0].element, true).width; + + // if there's no items, use size of container + } else { + size = containerWidth; } - // If the item will not change its position, do not add it to the render - // queue. Transitions don't fire when setting a property to the same value. - if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) { - item.applyCss(ShuffleItem.Css.VISIBLE.before); - callback(); - return; + // Don't let them set a column width of zero. + if (size === 0) { + size = containerWidth; } - item.point = itemPositions[i]; - item.scale = ShuffleItem.Scale.VISIBLE; - item.isHidden = false; + return size + gutterSize; + } - // Clone the object so that the `before` object isn't modified when the - // transition delay is added. - var styles = _this4.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before); - styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms'; + /** + * Returns the gutter size, based on gutter width and sizer options. + * @param {number} containerWidth Size of the parent container. + * @return {number} + * @private + */ + + }, { + key: '_getGutterSize', + value: function _getGutterSize(containerWidth) { + var size = void 0; + if (typeof this.options.gutterWidth === 'function') { + size = this.options.gutterWidth(containerWidth); + } else if (this.options.sizer) { + size = getNumberStyle(this.options.sizer, 'marginLeft'); + } else { + size = this.options.gutterWidth; + } - _this4._queue.push({ - item: item, - styles: styles, - callback: callback - }); + return size; + } - count += 1; - }); - } + /** + * Calculate the number of columns to be used. Gets css if using sizer element. + * @param {number} [containerWidth] Optionally specify a container width if + * it's already available. + */ + + }, { + key: '_setColumns', + value: function _setColumns() { + var containerWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Shuffle.getSize(this.element).width; + + var gutter = this._getGutterSize(containerWidth); + var columnWidth = this._getColumnSize(containerWidth, gutter); + var calculatedColumns = (containerWidth + gutter) / columnWidth; + + // Widths given from getStyles are not precise enough... + if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) < this.options.columnThreshold) { + // e.g. calculatedColumns = 11.998876 + calculatedColumns = Math.round(calculatedColumns); + } - /** - * Return an array of Point instances representing the future positions of - * each item. - * @param {ShuffleItem[]} items Array of sorted shuffle items. - * @return {Point[]} - * @private - */ + this.cols = Math.max(Math.floor(calculatedColumns), 1); + this.containerWidth = containerWidth; + this.colWidth = columnWidth; + } - }, { - key: '_getNextPositions', - value: function _getNextPositions(items) { - var _this5 = this; - - // If position data is going to be changed, add the item's size to the - // transformer to allow for calculations. - if (this.options.isCentered) { - var itemsData = items.map(function (item, i) { - var itemSize = Shuffle.getSize(item.element, true); - var point = _this5._getItemPosition(itemSize); - return new Rect(point.x, point.y, itemSize.width, itemSize.height, i); - }); + /** + * Adjust the height of the grid + */ - return this.getTransformedPositions(itemsData, this.containerWidth); + }, { + key: '_setContainerSize', + value: function _setContainerSize() { + this.element.style.height = this._getContainerSize() + 'px'; } - // If no transforms are going to happen, simply return an array of the - // future points of each item. - return items.map(function (item) { - return _this5._getItemPosition(Shuffle.getSize(item.element, true)); - }); - } + /** + * Based on the column heights, it returns the biggest one. + * @return {number} + * @private + */ - /** - * Determine the location of the next item, based on its size. - * @param {{width: number, height: number}} itemSize Object with width and height. - * @return {Point} - * @private - */ + }, { + key: '_getContainerSize', + value: function _getContainerSize() { + return arrayMax(this.positions); + } - }, { - key: '_getItemPosition', - value: function _getItemPosition(itemSize) { - return getItemPosition({ - itemSize: itemSize, - positions: this.positions, - gridSize: this.colWidth, - total: this.cols, - threshold: this.options.columnThreshold, - buffer: this.options.buffer - }); - } + /** + * Get the clamped stagger amount. + * @param {number} index Index of the item to be staggered. + * @return {number} + */ - /** - * Mutate positions before they're applied. - * @param {Rect[]} itemRects Item data objects. - * @param {number} containerWidth Width of the containing element. - * @return {Point[]} - * @protected - */ + }, { + key: '_getStaggerAmount', + value: function _getStaggerAmount(index) { + return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax); + } - }, { - key: 'getTransformedPositions', - value: function getTransformedPositions(itemRects, containerWidth) { - return getCenteredPositions(itemRects, containerWidth); - } + /** + * Emit an event from this instance. + * @param {string} name Event name. + * @param {Object} [data={}] Optional object data. + */ - /** - * Hides the elements that don't match our filter. - * @param {ShuffleItem[]} collection Collection to shrink. - * @private - */ + }, { + key: '_dispatch', + value: function _dispatch(name) { + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - }, { - key: '_shrink', - value: function _shrink() { - var _this6 = this; + if (this.isDestroyed) { + return; + } - var collection = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._getConcealedItems(); + data.shuffle = this; + this.emit(name, data); + } - var count = 0; - collection.forEach(function (item) { - function callback() { - item.applyCss(ShuffleItem.Css.HIDDEN.after); + /** + * Zeros out the y columns array, which is used to determine item placement. + * @private + */ + + }, { + key: '_resetCols', + value: function _resetCols() { + var i = this.cols; + this.positions = []; + while (i) { + i -= 1; + this.positions.push(0); } + } - // Continuing would add a transitionend event listener to the element, but - // that listener would not execute because the transform and opacity would - // stay the same. - // The callback is executed here because it is not guaranteed to be called - // after the transitionend event because the transitionend could be - // canceled if another animation starts. - if (item.isHidden) { - item.applyCss(ShuffleItem.Css.HIDDEN.before); - callback(); - return; - } + /** + * Loops through each item that should be shown and calculates the x, y position. + * @param {ShuffleItem[]} items Array of items that will be shown/layed + * out in order in their array. + */ - item.scale = ShuffleItem.Scale.HIDDEN; - item.isHidden = true; + }, { + key: '_layout', + value: function _layout(items) { + var _this4 = this; - var styles = _this6.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before); - styles.transitionDelay = _this6._getStaggerAmount(count) + 'ms'; + var itemPositions = this._getNextPositions(items); - _this6._queue.push({ - item: item, - styles: styles, - callback: callback - }); + var count = 0; + items.forEach(function (item, i) { + function callback() { + item.applyCss(ShuffleItem.Css.VISIBLE.after); + } - count += 1; - }); - } + // If the item will not change its position, do not add it to the render + // queue. Transitions don't fire when setting a property to the same value. + if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) { + item.applyCss(ShuffleItem.Css.VISIBLE.before); + callback(); + return; + } - /** - * Resize handler. - * @private - */ + item.point = itemPositions[i]; + item.scale = ShuffleItem.Scale.VISIBLE; + item.isHidden = false; + + // Clone the object so that the `before` object isn't modified when the + // transition delay is added. + var styles = _this4.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before); + styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms'; + + _this4._queue.push({ + item: item, + styles: styles, + callback: callback + }); - }, { - key: '_handleResize', - value: function _handleResize() { - // If shuffle is disabled, destroyed, don't do anything - if (!this.isEnabled || this.isDestroyed) { - return; + count += 1; + }); } - this.update(); - } + /** + * Return an array of Point instances representing the future positions of + * each item. + * @param {ShuffleItem[]} items Array of sorted shuffle items. + * @return {Point[]} + * @private + */ + + }, { + key: '_getNextPositions', + value: function _getNextPositions(items) { + var _this5 = this; + + // If position data is going to be changed, add the item's size to the + // transformer to allow for calculations. + if (this.options.isCentered) { + var itemsData = items.map(function (item, i) { + var itemSize = Shuffle.getSize(item.element, true); + var point = _this5._getItemPosition(itemSize); + return new Rect(point.x, point.y, itemSize.width, itemSize.height, i); + }); - /** - * Returns styles which will be applied to the an item for a transition. - * @param {ShuffleItem} item Item to get styles for. Should have updated - * scale and point properties. - * @param {Object} styleObject Extra styles that will be used in the transition. - * @return {!Object} Transforms for transitions, left/top for animate. - * @protected - */ + return this.getTransformedPositions(itemsData, this.containerWidth); + } - }, { - key: 'getStylesForTransition', - value: function getStylesForTransition(item, styleObject) { - // Clone the object to avoid mutating the original. - var styles = Object.assign({}, styleObject); + // If no transforms are going to happen, simply return an array of the + // future points of each item. + return items.map(function (item) { + return _this5._getItemPosition(Shuffle.getSize(item.element, true)); + }); + } - if (this.options.useTransforms) { - var x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x; - var y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y; - styles.transform = 'translate(' + x + 'px, ' + y + 'px) scale(' + item.scale + ')'; - } else { - styles.left = item.point.x + 'px'; - styles.top = item.point.y + 'px'; + /** + * Determine the location of the next item, based on its size. + * @param {{width: number, height: number}} itemSize Object with width and height. + * @return {Point} + * @private + */ + + }, { + key: '_getItemPosition', + value: function _getItemPosition(itemSize) { + return getItemPosition({ + itemSize: itemSize, + positions: this.positions, + gridSize: this.colWidth, + total: this.cols, + threshold: this.options.columnThreshold, + buffer: this.options.buffer + }); } - return styles; - } + /** + * Mutate positions before they're applied. + * @param {Rect[]} itemRects Item data objects. + * @param {number} containerWidth Width of the containing element. + * @return {Point[]} + * @protected + */ + + }, { + key: 'getTransformedPositions', + value: function getTransformedPositions(itemRects, containerWidth) { + return getCenteredPositions(itemRects, containerWidth); + } - /** - * Listen for the transition end on an element and execute the itemCallback - * when it finishes. - * @param {Element} element Element to listen on. - * @param {function} itemCallback Callback for the item. - * @param {function} done Callback to notify `parallel` that this one is done. - */ + /** + * Hides the elements that don't match our filter. + * @param {ShuffleItem[]} collection Collection to shrink. + * @private + */ - }, { - key: '_whenTransitionDone', - value: function _whenTransitionDone(element, itemCallback, done) { - var id = onTransitionEnd(element, function (evt) { - itemCallback(); - done(null, evt); - }); + }, { + key: '_shrink', + value: function _shrink() { + var _this6 = this; - this._transitions.push(id); - } + var collection = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._getConcealedItems(); - /** - * Return a function which will set CSS styles and call the `done` function - * when (if) the transition finishes. - * @param {Object} opts Transition object. - * @return {function} A function to be called with a `done` function. - */ + var count = 0; + collection.forEach(function (item) { + function callback() { + item.applyCss(ShuffleItem.Css.HIDDEN.after); + } - }, { - key: '_getTransitionFunction', - value: function _getTransitionFunction(opts) { - var _this7 = this; + // Continuing would add a transitionend event listener to the element, but + // that listener would not execute because the transform and opacity would + // stay the same. + // The callback is executed here because it is not guaranteed to be called + // after the transitionend event because the transitionend could be + // canceled if another animation starts. + if (item.isHidden) { + item.applyCss(ShuffleItem.Css.HIDDEN.before); + callback(); + return; + } - return function (done) { - opts.item.applyCss(opts.styles); - _this7._whenTransitionDone(opts.item.element, opts.callback, done); - }; - } + item.scale = ShuffleItem.Scale.HIDDEN; + item.isHidden = true; - /** - * Execute the styles gathered in the style queue. This applies styles to elements, - * triggering transitions. - * @private - */ + var styles = _this6.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before); + styles.transitionDelay = _this6._getStaggerAmount(count) + 'ms'; - }, { - key: '_processQueue', - value: function _processQueue() { - if (this.isTransitioning) { - this._cancelMovement(); + _this6._queue.push({ + item: item, + styles: styles, + callback: callback + }); + + count += 1; + }); } - var hasSpeed = this.options.speed > 0; - var hasQueue = this._queue.length > 0; + /** + * Resize handler. + * @private + */ - if (hasQueue && hasSpeed && this.isInitialized) { - this._startTransitions(this._queue); - } else if (hasQueue) { - this._styleImmediately(this._queue); - this._dispatch(Shuffle.EventType.LAYOUT); + }, { + key: '_handleResize', + value: function _handleResize() { + // If shuffle is disabled, destroyed, don't do anything + if (!this.isEnabled || this.isDestroyed) { + return; + } - // A call to layout happened, but none of the newly visible items will - // change position or the transition duration is zero, which will not trigger - // the transitionend event. - } else { - this._dispatch(Shuffle.EventType.LAYOUT); + this.update(); } - // Remove everything in the style queue - this._queue.length = 0; - } + /** + * Returns styles which will be applied to the an item for a transition. + * @param {ShuffleItem} item Item to get styles for. Should have updated + * scale and point properties. + * @param {Object} styleObject Extra styles that will be used in the transition. + * @return {!Object} Transforms for transitions, left/top for animate. + * @protected + */ + + }, { + key: 'getStylesForTransition', + value: function getStylesForTransition(item, styleObject) { + // Clone the object to avoid mutating the original. + var styles = Object.assign({}, styleObject); + + if (this.options.useTransforms) { + var x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x; + var y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y; + styles.transform = 'translate(' + x + 'px, ' + y + 'px) scale(' + item.scale + ')'; + } else { + styles.left = item.point.x + 'px'; + styles.top = item.point.y + 'px'; + } - /** - * Wait for each transition to finish, the emit the layout event. - * @param {Object[]} transitions Array of transition objects. - */ + return styles; + } - }, { - key: '_startTransitions', - value: function _startTransitions(transitions) { - var _this8 = this; + /** + * Listen for the transition end on an element and execute the itemCallback + * when it finishes. + * @param {Element} element Element to listen on. + * @param {function} itemCallback Callback for the item. + * @param {function} done Callback to notify `parallel` that this one is done. + */ + + }, { + key: '_whenTransitionDone', + value: function _whenTransitionDone(element, itemCallback, done) { + var id = onTransitionEnd(element, function (evt) { + itemCallback(); + done(null, evt); + }); - // Set flag that shuffle is currently in motion. - this.isTransitioning = true; + this._transitions.push(id); + } - // Create an array of functions to be called. - var callbacks = transitions.map(function (obj) { - return _this8._getTransitionFunction(obj); - }); + /** + * Return a function which will set CSS styles and call the `done` function + * when (if) the transition finishes. + * @param {Object} opts Transition object. + * @return {function} A function to be called with a `done` function. + */ + + }, { + key: '_getTransitionFunction', + value: function _getTransitionFunction(opts) { + var _this7 = this; + + return function (done) { + opts.item.applyCss(opts.styles); + _this7._whenTransitionDone(opts.item.element, opts.callback, done); + }; + } - arrayParallel(callbacks, this._movementFinished.bind(this)); - } - }, { - key: '_cancelMovement', - value: function _cancelMovement() { - // Remove the transition end event for each listener. - this._transitions.forEach(cancelTransitionEnd); + /** + * Execute the styles gathered in the style queue. This applies styles to elements, + * triggering transitions. + * @private + */ + + }, { + key: '_processQueue', + value: function _processQueue() { + if (this.isTransitioning) { + this._cancelMovement(); + } - // Reset the array. - this._transitions.length = 0; + var hasSpeed = this.options.speed > 0; + var hasQueue = this._queue.length > 0; - // Show it's no longer active. - this.isTransitioning = false; - } + if (hasQueue && hasSpeed && this.isInitialized) { + this._startTransitions(this._queue); + } else if (hasQueue) { + this._styleImmediately(this._queue); + this._dispatch(Shuffle.EventType.LAYOUT); - /** - * Apply styles without a transition. - * @param {Object[]} objects Array of transition objects. - * @private - */ + // A call to layout happened, but none of the newly visible items will + // change position or the transition duration is zero, which will not trigger + // the transitionend event. + } else { + this._dispatch(Shuffle.EventType.LAYOUT); + } - }, { - key: '_styleImmediately', - value: function _styleImmediately(objects) { - if (objects.length) { - var elements = objects.map(function (obj) { - return obj.item.element; - }); + // Remove everything in the style queue + this._queue.length = 0; + } - Shuffle._skipTransitions(elements, function () { - objects.forEach(function (obj) { - obj.item.applyCss(obj.styles); - obj.callback(); - }); + /** + * Wait for each transition to finish, the emit the layout event. + * @param {Object[]} transitions Array of transition objects. + */ + + }, { + key: '_startTransitions', + value: function _startTransitions(transitions) { + var _this8 = this; + + // Set flag that shuffle is currently in motion. + this.isTransitioning = true; + + // Create an array of functions to be called. + var callbacks = transitions.map(function (obj) { + return _this8._getTransitionFunction(obj); }); + + arrayParallel(callbacks, this._movementFinished.bind(this)); } - } - }, { - key: '_movementFinished', - value: function _movementFinished() { - this._transitions.length = 0; - this.isTransitioning = false; - this._dispatch(Shuffle.EventType.LAYOUT); - } + }, { + key: '_cancelMovement', + value: function _cancelMovement() { + // Remove the transition end event for each listener. + this._transitions.forEach(cancelTransitionEnd); - /** - * The magic. This is what makes the plugin 'shuffle' - * @param {string|string[]|function(Element):boolean} [category] Category to filter by. - * Can be a function, string, or array of strings. - * @param {Object} [sortObj] A sort object which can sort the visible set - */ + // Reset the array. + this._transitions.length = 0; - }, { - key: 'filter', - value: function filter(category, sortObj) { - if (!this.isEnabled) { - return; + // Show it's no longer active. + this.isTransitioning = false; } - if (!category || category && category.length === 0) { - category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign - } + /** + * Apply styles without a transition. + * @param {Object[]} objects Array of transition objects. + * @private + */ + + }, { + key: '_styleImmediately', + value: function _styleImmediately(objects) { + if (objects.length) { + var elements = objects.map(function (obj) { + return obj.item.element; + }); - this._filter(category); + Shuffle._skipTransitions(elements, function () { + objects.forEach(function (obj) { + obj.item.applyCss(obj.styles); + obj.callback(); + }); + }); + } + } + }, { + key: '_movementFinished', + value: function _movementFinished() { + this._transitions.length = 0; + this.isTransitioning = false; + this._dispatch(Shuffle.EventType.LAYOUT); + } - // Shrink each hidden item - this._shrink(); + /** + * The magic. This is what makes the plugin 'shuffle' + * @param {string|string[]|function(Element):boolean} [category] Category to filter by. + * Can be a function, string, or array of strings. + * @param {Object} [sortObj] A sort object which can sort the visible set + */ + + }, { + key: 'filter', + value: function filter(category, sortObj) { + if (!this.isEnabled) { + return; + } - // How many visible elements? - this._updateItemCount(); + if (!category || category && category.length === 0) { + category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign + } - // Update transforms on visible elements so they will animate to their new positions. - this.sort(sortObj); - } + this._filter(category); - /** - * Gets the visible elements, sorts them, and passes them to layout. - * @param {Object} [sortOptions] The options object to pass to `sorter`. - */ + // Shrink each hidden item + this._shrink(); - }, { - key: 'sort', - value: function sort() { - var sortOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort; + // How many visible elements? + this._updateItemCount(); - if (!this.isEnabled) { - return; + // Update transforms on visible elements so they will animate to their new positions. + this.sort(sortObj); } - this._resetCols(); - - var items = sorter(this._getFilteredItems(), sortOptions); + /** + * Gets the visible elements, sorts them, and passes them to layout. + * @param {Object} [sortOptions] The options object to pass to `sorter`. + */ - this._layout(items); + }, { + key: 'sort', + value: function sort() { + var sortOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort; - // `_layout` always happens after `_shrink`, so it's safe to process the style - // queue here with styles from the shrink method. - this._processQueue(); + if (!this.isEnabled) { + return; + } - // Adjust the height of the container. - this._setContainerSize(); + this._resetCols(); - this.lastSort = sortOptions; - } + var items = sorter(this._getFilteredItems(), sortOptions); - /** - * Reposition everything. - * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated. - */ + this._layout(items); - }, { - key: 'update', - value: function update() { - var isOnlyLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + // `_layout` always happens after `_shrink`, so it's safe to process the style + // queue here with styles from the shrink method. + this._processQueue(); - if (this.isEnabled) { - if (!isOnlyLayout) { - // Get updated colCount - this._setColumns(); - } + // Adjust the height of the container. + this._setContainerSize(); - // Layout items - this.sort(); + this.lastSort = sortOptions; } - } - /** - * Use this instead of `update()` if you don't need the columns and gutters updated - * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations - * could be off. - */ + /** + * Reposition everything. + * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated. + */ - }, { - key: 'layout', - value: function layout() { - this.update(true); - } + }, { + key: 'update', + value: function update() { + var isOnlyLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - /** - * New items have been appended to shuffle. Mix them in with the current - * filter or sort status. - * @param {Element[]} newItems Collection of new items. - */ + if (this.isEnabled) { + if (!isOnlyLayout) { + // Get updated colCount + this._setColumns(); + } - }, { - key: 'add', - value: function add(newItems) { - var _this9 = this; + // Layout items + this.sort(); + } + } - var items = arrayUnique(newItems).map(function (el) { - return new ShuffleItem(el); - }); + /** + * Use this instead of `update()` if you don't need the columns and gutters updated + * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations + * could be off. + */ - // Add classes and set initial positions. - this._initItems(items); - - // Determine which items will go with the current filter. - this._resetCols(); - - var allItems = this._mergeNewItems(items); - var sortedItems = sorter(allItems, this.lastSort); - var allSortedItemsSet = this._filter(this.lastFilter, sortedItems); - - var isNewItem = function isNewItem(item) { - return items.includes(item); - }; - var applyHiddenState = function applyHiddenState(item) { - item.scale = ShuffleItem.Scale.HIDDEN; - item.isHidden = true; - item.applyCss(ShuffleItem.Css.HIDDEN.before); - item.applyCss(ShuffleItem.Css.HIDDEN.after); - }; - - // Layout all items again so that new items get positions. - // Synchonously apply positions. - var itemPositions = this._getNextPositions(allSortedItemsSet.visible); - allSortedItemsSet.visible.forEach(function (item, i) { - if (isNewItem(item)) { - item.point = itemPositions[i]; - applyHiddenState(item); - item.applyCss(_this9.getStylesForTransition(item, {})); - } - }); + }, { + key: 'layout', + value: function layout() { + this.update(true); + } - allSortedItemsSet.hidden.forEach(function (item) { - if (isNewItem(item)) { - applyHiddenState(item); - } - }); + /** + * New items have been appended to shuffle. Mix them in with the current + * filter or sort status. + * @param {Element[]} newItems Collection of new items. + */ - // Cause layout so that the styles above are applied. - this.element.offsetWidth; // eslint-disable-line no-unused-expressions + }, { + key: 'add', + value: function add(newItems) { + var _this9 = this; - // Add transition to each item. - this.setItemTransitions(items); + var items = arrayUnique(newItems).map(function (el) { + return new ShuffleItem(el); + }); - // Update the list of items. - this.items = this._mergeNewItems(items); + // Add classes and set initial positions. + this._initItems(items); - // Update layout/visibility of new and old items. - this.filter(this.lastFilter); - } + // Determine which items will go with the current filter. + this._resetCols(); - /** - * Disables shuffle from updating dimensions and layout on resize - */ + var allItems = this._mergeNewItems(items); + var sortedItems = sorter(allItems, this.lastSort); + var allSortedItemsSet = this._filter(this.lastFilter, sortedItems); - }, { - key: 'disable', - value: function disable() { - this.isEnabled = false; - } + var isNewItem = function isNewItem(item) { + return items.includes(item); + }; + var applyHiddenState = function applyHiddenState(item) { + item.scale = ShuffleItem.Scale.HIDDEN; + item.isHidden = true; + item.applyCss(ShuffleItem.Css.HIDDEN.before); + item.applyCss(ShuffleItem.Css.HIDDEN.after); + }; - /** - * Enables shuffle again - * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters - */ + // Layout all items again so that new items get positions. + // Synchonously apply positions. + var itemPositions = this._getNextPositions(allSortedItemsSet.visible); + allSortedItemsSet.visible.forEach(function (item, i) { + if (isNewItem(item)) { + item.point = itemPositions[i]; + applyHiddenState(item); + item.applyCss(_this9.getStylesForTransition(item, {})); + } + }); - }, { - key: 'enable', - value: function enable() { - var isUpdateLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + allSortedItemsSet.hidden.forEach(function (item) { + if (isNewItem(item)) { + applyHiddenState(item); + } + }); - this.isEnabled = true; - if (isUpdateLayout) { - this.update(); - } - } + // Cause layout so that the styles above are applied. + this.element.offsetWidth; // eslint-disable-line no-unused-expressions - /** - * Remove 1 or more shuffle items. - * @param {Element[]} elements An array containing one or more - * elements in shuffle - * @return {Shuffle} The shuffle instance. - */ + // Add transition to each item. + this.setItemTransitions(items); - }, { - key: 'remove', - value: function remove(elements) { - var _this10 = this; + // Update the list of items. + this.items = this._mergeNewItems(items); - if (!elements.length) { - return; + // Update layout/visibility of new and old items. + this.filter(this.lastFilter); } - var collection = arrayUnique(elements); + /** + * Disables shuffle from updating dimensions and layout on resize + */ - var oldItems = collection.map(function (element) { - return _this10.getItemByElement(element); - }).filter(function (item) { - return !!item; - }); + }, { + key: 'disable', + value: function disable() { + this.isEnabled = false; + } - var handleLayout = function handleLayout() { - _this10._disposeItems(oldItems); + /** + * Enables shuffle again + * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters + */ - // Remove the collection in the callback - collection.forEach(function (element) { - element.parentNode.removeChild(element); - }); + }, { + key: 'enable', + value: function enable() { + var isUpdateLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; - _this10._dispatch(Shuffle.EventType.REMOVED, { collection: collection }); - }; + this.isEnabled = true; + if (isUpdateLayout) { + this.update(); + } + } - // Hide collection first. - this._toggleFilterClasses({ - visible: [], - hidden: oldItems - }); + /** + * Remove 1 or more shuffle items. + * @param {Element[]} elements An array containing one or more + * elements in shuffle + * @return {Shuffle} The shuffle instance. + */ - this._shrink(oldItems); + }, { + key: 'remove', + value: function remove(elements) { + var _this10 = this; - this.sort(); + if (!elements.length) { + return; + } - // Update the list of items here because `remove` could be called again - // with an item that is in the process of being removed. - this.items = this.items.filter(function (item) { - return !oldItems.includes(item); - }); - this._updateItemCount(); + var collection = arrayUnique(elements); - this.once(Shuffle.EventType.LAYOUT, handleLayout); - } + var oldItems = collection.map(function (element) { + return _this10.getItemByElement(element); + }).filter(function (item) { + return !!item; + }); - /** - * Retrieve a shuffle item by its element. - * @param {Element} element Element to look for. - * @return {?ShuffleItem} A shuffle item or undefined if it's not found. - */ + var handleLayout = function handleLayout() { + _this10._disposeItems(oldItems); - }, { - key: 'getItemByElement', - value: function getItemByElement(element) { - return this.items.find(function (item) { - return item.element === element; - }); - } + // Remove the collection in the callback + collection.forEach(function (element) { + element.parentNode.removeChild(element); + }); - /** - * Dump the elements currently stored and reinitialize all child elements which - * match the `itemSelector`. - */ + _this10._dispatch(Shuffle.EventType.REMOVED, { collection: collection }); + }; - }, { - key: 'resetItems', - value: function resetItems() { - var _this11 = this; + // Hide collection first. + this._toggleFilterClasses({ + visible: [], + hidden: oldItems + }); - // Remove refs to current items. - this._disposeItems(this.items); - this.isInitialized = false; + this._shrink(oldItems); - // Find new items in the DOM. - this.items = this._getItems(); + this.sort(); - // Set initial styles on the new items. - this._initItems(this.items); + // Update the list of items here because `remove` could be called again + // with an item that is in the process of being removed. + this.items = this.items.filter(function (item) { + return !oldItems.includes(item); + }); + this._updateItemCount(); - this.once(Shuffle.EventType.LAYOUT, function () { - // Add transition to each item. - _this11.setItemTransitions(_this11.items); - _this11.isInitialized = true; - }); + this.once(Shuffle.EventType.LAYOUT, handleLayout); + } - // Lay out all items. - this.filter(this.lastFilter); - } + /** + * Retrieve a shuffle item by its element. + * @param {Element} element Element to look for. + * @return {?ShuffleItem} A shuffle item or undefined if it's not found. + */ + + }, { + key: 'getItemByElement', + value: function getItemByElement(element) { + return this.items.find(function (item) { + return item.element === element; + }); + } - /** - * Destroys shuffle, removes events, styles, and classes - */ + /** + * Dump the elements currently stored and reinitialize all child elements which + * match the `itemSelector`. + */ - }, { - key: 'destroy', - value: function destroy() { - this._cancelMovement(); - window.removeEventListener('resize', this._onResize); + }, { + key: 'resetItems', + value: function resetItems() { + var _this11 = this; - // Reset container styles - this.element.classList.remove('shuffle'); - this.element.removeAttribute('style'); + // Remove refs to current items. + this._disposeItems(this.items); + this.isInitialized = false; - // Reset individual item styles - this._disposeItems(this.items); + // Find new items in the DOM. + this.items = this._getItems(); - this.items.length = 0; - this._transitions.length = 0; + // Set initial styles on the new items. + this._initItems(this.items); - // Null DOM references - this.options.sizer = null; - this.element = null; + this.once(Shuffle.EventType.LAYOUT, function () { + // Add transition to each item. + _this11.setItemTransitions(_this11.items); + _this11.isInitialized = true; + }); - // Set a flag so if a debounced resize has been triggered, - // it can first check if it is actually isDestroyed and not doing anything - this.isDestroyed = true; - this.isEnabled = false; - } + // Lay out all items. + this.filter(this.lastFilter); + } - /** - * Returns the outer width of an element, optionally including its margins. - * - * There are a few different methods for getting the width of an element, none of - * which work perfectly for all Shuffle's use cases. - * - * 1. getBoundingClientRect() `left` and `right` properties. - * - Accounts for transform scaled elements, making it useless for Shuffle - * elements which have shrunk. - * 2. The `offsetWidth` property. - * - This value stays the same regardless of the elements transform property, - * however, it does not return subpixel values. - * 3. getComputedStyle() - * - This works great Chrome, Firefox, Safari, but IE<=11 does not include - * padding and border when box-sizing: border-box is set, requiring a feature - * test and extra work to add the padding back for IE and other browsers which - * follow the W3C spec here. - * - * @param {Element} element The element. - * @param {boolean} [includeMargins=false] Whether to include margins. - * @return {{width: number, height: number}} The width and height. - */ + /** + * Destroys shuffle, removes events, styles, and classes + */ - }], [{ - key: 'getSize', - value: function getSize(element) { - var includeMargins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - // Store the styles so that they can be used by others without asking for it again. - var styles = window.getComputedStyle(element, null); - var width = getNumberStyle(element, 'width', styles); - var height = getNumberStyle(element, 'height', styles); - - if (includeMargins) { - var marginLeft = getNumberStyle(element, 'marginLeft', styles); - var marginRight = getNumberStyle(element, 'marginRight', styles); - var marginTop = getNumberStyle(element, 'marginTop', styles); - var marginBottom = getNumberStyle(element, 'marginBottom', styles); - width += marginLeft + marginRight; - height += marginTop + marginBottom; - } - - return { - width: width, - height: height - }; - } + }, { + key: 'destroy', + value: function destroy() { + this._cancelMovement(); + window.removeEventListener('resize', this._onResize); - /** - * Change a property or execute a function which will not have a transition - * @param {Element[]} elements DOM elements that won't be transitioned. - * @param {function} callback A function which will be called while transition - * is set to 0ms. - * @private - */ + // Reset container styles + this.element.classList.remove('shuffle'); + this.element.removeAttribute('style'); - }, { - key: '_skipTransitions', - value: function _skipTransitions(elements, callback) { - var zero = '0ms'; + // Reset individual item styles + this._disposeItems(this.items); - // Save current duration and delay. - var data = elements.map(function (element) { - var style = element.style; + this.items.length = 0; + this._transitions.length = 0; - var duration = style.transitionDuration; - var delay = style.transitionDelay; + // Null DOM references + this.options.sizer = null; + this.element = null; - // Set the duration to zero so it happens immediately - style.transitionDuration = zero; - style.transitionDelay = zero; + // Set a flag so if a debounced resize has been triggered, + // it can first check if it is actually isDestroyed and not doing anything + this.isDestroyed = true; + this.isEnabled = false; + } + + /** + * Returns the outer width of an element, optionally including its margins. + * + * There are a few different methods for getting the width of an element, none of + * which work perfectly for all Shuffle's use cases. + * + * 1. getBoundingClientRect() `left` and `right` properties. + * - Accounts for transform scaled elements, making it useless for Shuffle + * elements which have shrunk. + * 2. The `offsetWidth` property. + * - This value stays the same regardless of the elements transform property, + * however, it does not return subpixel values. + * 3. getComputedStyle() + * - This works great Chrome, Firefox, Safari, but IE<=11 does not include + * padding and border when box-sizing: border-box is set, requiring a feature + * test and extra work to add the padding back for IE and other browsers which + * follow the W3C spec here. + * + * @param {Element} element The element. + * @param {boolean} [includeMargins=false] Whether to include margins. + * @return {{width: number, height: number}} The width and height. + */ + + }], [{ + key: 'getSize', + value: function getSize(element) { + var includeMargins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + // Store the styles so that they can be used by others without asking for it again. + var styles = window.getComputedStyle(element, null); + var width = getNumberStyle(element, 'width', styles); + var height = getNumberStyle(element, 'height', styles); + + if (includeMargins) { + var marginLeft = getNumberStyle(element, 'marginLeft', styles); + var marginRight = getNumberStyle(element, 'marginRight', styles); + var marginTop = getNumberStyle(element, 'marginTop', styles); + var marginBottom = getNumberStyle(element, 'marginBottom', styles); + width += marginLeft + marginRight; + height += marginTop + marginBottom; + } return { - duration: duration, - delay: delay + width: width, + height: height }; - }); + } - callback(); + /** + * Change a property or execute a function which will not have a transition + * @param {Element[]} elements DOM elements that won't be transitioned. + * @param {function} callback A function which will be called while transition + * is set to 0ms. + * @private + */ + + }, { + key: '_skipTransitions', + value: function _skipTransitions(elements, callback) { + var zero = '0ms'; + + // Save current duration and delay. + var data = elements.map(function (element) { + var style = element.style; + + var duration = style.transitionDuration; + var delay = style.transitionDelay; + + // Set the duration to zero so it happens immediately + style.transitionDuration = zero; + style.transitionDelay = zero; + + return { + duration: duration, + delay: delay + }; + }); - // Cause forced synchronous layout. - elements[0].offsetWidth; // eslint-disable-line no-unused-expressions + callback(); - // Put the duration back - elements.forEach(function (element, i) { - element.style.transitionDuration = data[i].duration; - element.style.transitionDelay = data[i].delay; - }); - } - }]); - return Shuffle; -}(tinyEmitter); + // Cause forced synchronous layout. + elements[0].offsetWidth; // eslint-disable-line no-unused-expressions + + // Put the duration back + elements.forEach(function (element, i) { + element.style.transitionDuration = data[i].duration; + element.style.transitionDelay = data[i].delay; + }); + } + }]); + return Shuffle; + }(tinyEmitter); -Shuffle.ShuffleItem = ShuffleItem; + Shuffle.ShuffleItem = ShuffleItem; -Shuffle.ALL_ITEMS = 'all'; -Shuffle.FILTER_ATTRIBUTE_KEY = 'groups'; + Shuffle.ALL_ITEMS = 'all'; + Shuffle.FILTER_ATTRIBUTE_KEY = 'groups'; -/** @enum {string} */ -Shuffle.EventType = { - LAYOUT: 'shuffle:layout', - REMOVED: 'shuffle:removed' -}; + /** @enum {string} */ + Shuffle.EventType = { + LAYOUT: 'shuffle:layout', + REMOVED: 'shuffle:removed' + }; -/** @enum {string} */ -Shuffle.Classes = Classes; + /** @enum {string} */ + Shuffle.Classes = Classes; -/** @enum {string} */ -Shuffle.FilterMode = { - ANY: 'any', - ALL: 'all' -}; + /** @enum {string} */ + Shuffle.FilterMode = { + ANY: 'any', + ALL: 'all' + }; -// Overrideable options -Shuffle.options = { - // Initial filter group. - group: Shuffle.ALL_ITEMS, + // Overrideable options + Shuffle.options = { + // Initial filter group. + group: Shuffle.ALL_ITEMS, - // Transition/animation speed (milliseconds). - speed: 250, + // Transition/animation speed (milliseconds). + speed: 250, - // CSS easing function to use. - easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', + // CSS easing function to use. + easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', - // e.g. '.picture-item'. - itemSelector: '*', + // e.g. '.picture-item'. + itemSelector: '*', - // Element or selector string. Use an element to determine the size of columns - // and gutters. - sizer: null, + // Element or selector string. Use an element to determine the size of columns + // and gutters. + sizer: null, - // A static number or function that tells the plugin how wide the gutters - // between columns are (in pixels). - gutterWidth: 0, + // A static number or function that tells the plugin how wide the gutters + // between columns are (in pixels). + gutterWidth: 0, - // A static number or function that returns a number which tells the plugin - // how wide the columns are (in pixels). - columnWidth: 0, + // A static number or function that returns a number which tells the plugin + // how wide the columns are (in pixels). + columnWidth: 0, - // If your group is not json, and is comma delimeted, you could set delimiter - // to ','. - delimiter: null, + // If your group is not json, and is comma delimeted, you could set delimiter + // to ','. + delimiter: null, - // Useful for percentage based heights when they might not always be exactly - // the same (in pixels). - buffer: 0, + // Useful for percentage based heights when they might not always be exactly + // the same (in pixels). + buffer: 0, - // Reading the width of elements isn't precise enough and can cause columns to - // jump between values. - columnThreshold: 0.01, + // Reading the width of elements isn't precise enough and can cause columns to + // jump between values. + columnThreshold: 0.01, - // Shuffle can be isInitialized with a sort object. It is the same object - // given to the sort method. - initialSort: null, + // Shuffle can be isInitialized with a sort object. It is the same object + // given to the sort method. + initialSort: null, - // By default, shuffle will throttle resize events. This can be changed or - // removed. - throttle: throttleit, + // By default, shuffle will throttle resize events. This can be changed or + // removed. + throttle: throttleit, - // How often shuffle can be called on resize (in milliseconds). - throttleTime: 300, + // How often shuffle can be called on resize (in milliseconds). + throttleTime: 300, - // Transition delay offset for each item in milliseconds. - staggerAmount: 15, + // Transition delay offset for each item in milliseconds. + staggerAmount: 15, - // Maximum stagger delay in milliseconds. - staggerAmountMax: 150, + // Maximum stagger delay in milliseconds. + staggerAmountMax: 150, - // Whether to use transforms or absolute positioning. - useTransforms: true, + // Whether to use transforms or absolute positioning. + useTransforms: true, - // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With "any", - // the element passes the test if any of its groups are in the array. With "all", - // the element only passes if all groups are in the array. - filterMode: Shuffle.FilterMode.ANY, + // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With "any", + // the element passes the test if any of its groups are in the array. With "all", + // the element only passes if all groups are in the array. + filterMode: Shuffle.FilterMode.ANY, - // Attempt to center grid items in each row. - isCentered: false, + // Attempt to center grid items in each row. + isCentered: false, - // Whether to round pixel values used in translate(x, y). This usually avoids - // blurriness. - roundTransforms: true -}; + // Whether to round pixel values used in translate(x, y). This usually avoids + // blurriness. + roundTransforms: true + }; -Shuffle.Point = Point; -Shuffle.Rect = Rect; + Shuffle.Point = Point; + Shuffle.Rect = Rect; -// Expose for testing. Hack at your own risk. -Shuffle.__sorter = sorter; -Shuffle.__getColumnSpan = getColumnSpan; -Shuffle.__getAvailablePositions = getAvailablePositions; -Shuffle.__getShortColumn = getShortColumn; -Shuffle.__getCenteredPositions = getCenteredPositions; + // Expose for testing. Hack at your own risk. + Shuffle.__sorter = sorter; + Shuffle.__getColumnSpan = getColumnSpan; + Shuffle.__getAvailablePositions = getAvailablePositions; + Shuffle.__getShortColumn = getShortColumn; + Shuffle.__getCenteredPositions = getCenteredPositions; -return Shuffle; + return Shuffle; }))); //# sourceMappingURL=shuffle.js.map diff --git a/dist/shuffle.js.map b/dist/shuffle.js.map index 1fb316f..fe2c3b6 100644 --- a/dist/shuffle.js.map +++ b/dist/shuffle.js.map @@ -1 +1 @@ -{"version":3,"file":"shuffle.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/hyphenate.js","../src/shuffle.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n"],"names":["getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","e","createElement","cssText","appendChild","window","getComputedStyle","ret","removeChild","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","randomize","array","n","length","i","Math","floor","random","temp","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","by","sort","valA","valB","undefined","compare","reverse","transitions","eventName","count","uniqueId","cancelTransitionEnd","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","slice","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","setY","shortColumnIndex","setHeight","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","hasOverlap","rowIndex","findIndex","items","includes","splice","concat","map","hyphenate","str","replace","m1","toLowerCase","arrayUnique","Set","Shuffle","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","el","_getElementOption","TypeError","_init","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","nodeType","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_doesPassFilter","call","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","before","k","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","matches","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","data","shuffle","emit","itemPositions","_getNextPositions","after","equals","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","_getItemPosition","getTransformedPositions","_getConcealedItems","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","callbacks","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","allItems","_mergeNewItems","sortedItems","allSortedItemsSet","isNewItem","applyHiddenState","isUpdateLayout","oldItems","getItemByElement","handleLayout","_disposeItems","parentNode","REMOVED","once","find","includeMargins","marginLeft","marginRight","marginTop","marginBottom","zero","duration","delay","TinyEmitter","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"shuffle.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/hyphenate.js","../src/shuffle.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n"],"names":["getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","BASE","SHUFFLE_ITEM","VISIBLE","HIDDEN","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","add","removeAttribute","setAttribute","addClasses","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","Object","keys","key","style","removeClasses","position","visibility","before","opacity","after","transitionDelay","document","body","documentElement","e","createElement","cssText","appendChild","window","getComputedStyle","ret","removeChild","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","randomize","array","n","length","i","Math","floor","random","temp","defaults","reverse","by","compare","sorter","arr","options","opts","assign","original","Array","from","revert","sort","valA","valB","undefined","transitions","eventName","count","uniqueId","cancelTransitionEnd","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","slice","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","setY","shortColumnIndex","setHeight","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","hasOverlap","rowIndex","findIndex","items","includes","splice","concat","map","hyphenate","str","replace","m1","toLowerCase","arrayUnique","Set","Shuffle","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","el","_getElementOption","TypeError","_init","_getItems","sizer","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","nodeType","jquery","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_doesPassFilter","call","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","k","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","matches","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","data","shuffle","emit","itemPositions","_getNextPositions","equals","getStylesForTransition","_getStaggerAmount","isCentered","itemsData","_getItemPosition","getTransformedPositions","_getConcealedItems","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","callbacks","_getTransitionFunction","parallel","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","allItems","_mergeNewItems","sortedItems","allSortedItemsSet","isNewItem","applyHiddenState","isUpdateLayout","oldItems","getItemByElement","handleLayout","_disposeItems","parentNode","REMOVED","once","find","includeMargins","marginLeft","marginRight","marginTop","marginBottom","zero","duration","delay","TinyEmitter","ALL","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file diff --git a/dist/shuffle.min.js.map b/dist/shuffle.min.js.map index 4f71422..5c53804 100644 --- a/dist/shuffle.min.js.map +++ b/dist/shuffle.min.js.map @@ -1 +1 @@ -{"version":3,"file":"shuffle.min.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/layout.js","../src/array-min.js","../src/shuffle.js","../src/hyphenate.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n"],"names":["E","prototype","on","name","callback","ctx","e","this","push","fn","once","self","listener","off","apply","arguments","_","emit","data","slice","call","evtArr","i","len","length","evts","liveEvents","proto","Element","vendor","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","el","selector","nodeType","nodes","parentNode","querySelectorAll","func","wait","args","rtn","timeoutID","last","delta","Date","setTimeout","noop","getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","createElement","cssText","appendChild","ret","window","getComputedStyle","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","removeChild","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","randomize","array","n","Math","floor","random","temp","by","sort","valA","valB","undefined","compare","reverse","transitions","eventName","count","cancelTransitionEnd","removeEventListener","onTransitionEnd","evt","currentTarget","target","addEventListener","arrayMax","max","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","min","ceil","getAvailablePositions","positions","available","getShortColumn","buffer","minPosition","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","rowIndex","findIndex","items","includes","splice","concat","map","arrayUnique","Set","Shuffle","_this","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","_getElementOption","TypeError","_init","TinyEmitter","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_this2","_doesPassFilter","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","before","k","replace","str","m1","toLowerCase","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","_this3","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","shuffle","itemPositions","_getNextPositions","after","equals","_this4","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","itemSize","_this5","_getItemPosition","getTransformedPositions","gridSize","total","span","setY","shortColumnIndex","setHeight","getItemPosition","_getConcealedItems","_this6","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","fns","context","pending","finished","results","maybeDone","err","result","_this8","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","sortedItems","_mergeNewItems","allSortedItemsSet","isNewItem","applyHiddenState","_this9","isUpdateLayout","oldItems","_this10","getItemByElement","_disposeItems","REMOVED","find","_this11","includeMargins","duration","delay","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"mLAAA,SAASA,KAKTA,EAAEC,WACAC,GAAI,SAAUC,EAAMC,EAAUC,GAC5B,IAAIC,EAAIC,KAAKD,IAAMC,KAAKD,MAOxB,OALCA,EAAEH,KAAUG,EAAEH,QAAaK,MAC1BC,GAAIL,EACJC,IAAKA,IAGAE,MAGTG,KAAM,SAAUP,EAAMC,EAAUC,GAC9B,IAAIM,EAAOJ,KACX,SAASK,IACPD,EAAKE,IAAIV,EAAMS,GACfR,EAASU,MAAMT,EAAKU,WAItB,OADAH,EAASI,EAAIZ,EACNG,KAAKL,GAAGC,EAAMS,EAAUP,IAGjCY,KAAM,SAAUd,GAMd,IALA,IAAIe,KAAUC,MAAMC,KAAKL,UAAW,GAChCM,IAAWd,KAAKD,IAAMC,KAAKD,OAASH,QAAagB,QACjDG,EAAI,EACJC,EAAMF,EAAOG,OAETF,EAAIC,EAAKD,IACfD,EAAOC,GAAGb,GAAGK,MAAMO,EAAOC,GAAGjB,IAAKa,GAGpC,OAAOX,MAGTM,IAAK,SAAUV,EAAMC,GACnB,IAAIE,EAAIC,KAAKD,IAAMC,KAAKD,MACpBmB,EAAOnB,EAAEH,GACTuB,KAEJ,GAAID,GAAQrB,EACV,IAAK,IAAIkB,EAAI,EAAGC,EAAME,EAAKD,OAAQF,EAAIC,EAAKD,IACtCG,EAAKH,GAAGb,KAAOL,GAAYqB,EAAKH,GAAGb,GAAGO,IAAMZ,GAC9CsB,EAAWlB,KAAKiB,EAAKH,IAY3B,OAJCI,EAAiB,OACdpB,EAAEH,GAAQuB,SACHpB,EAAEH,GAENI,OAIX,MAAiBP,EC/Db2B,EAA2B,oBAAZC,QAA0BA,QAAQ3B,aACjD4B,EAASF,EAAMG,SACdH,EAAMI,iBACNJ,EAAMK,uBACNL,EAAMM,oBACNN,EAAMO,mBACNP,EAAMQ,mBAaX,SAAeC,EAAIC,GACjB,IAAKD,GAAsB,IAAhBA,EAAGE,SAAgB,OAAO,EACrC,GAAIT,EAAQ,OAAOA,EAAOT,KAAKgB,EAAIC,GAEnC,IADA,IAAIE,EAAQH,EAAGI,WAAWC,iBAAiBJ,GAClCf,EAAI,EAAGA,EAAIiB,EAAMf,OAAQF,IAChC,GAAIiB,EAAMjB,IAAMc,EAAI,OAAO,EAE7B,OAAO,GC5BT,MAUA,SAAmBM,EAAMC,GACvB,IAAItC,EAAKuC,EAAMC,EAAKC,EAChBC,EAAO,EAEX,OAAO,WACL1C,EAAME,KACNqC,EAAO7B,UACP,IAAIiC,EAAQ,IAAIC,KAASF,EAIzB,OAHKD,IACCE,GAASL,EAAMvB,IACd0B,EAAYI,WAAW9B,EAAMuB,EAAOK,IACpCH,GAGT,SAASzB,IACP0B,EAAY,EACZC,GAAQ,IAAIE,KACZJ,EAAMH,EAAK5B,MAAMT,EAAKuC,GACtBvC,EAAM,KACNuC,EAAO,OCUX,SAASO,KClCT,SAAwBC,EAAUC,UACzBC,WAAWD,IAAU,8fCJxBE,wBAMQC,EAAGC,kBACRD,EAAIJ,EAAUI,QACdC,EAAIL,EAAUK,iDASPC,EAAGC,UACRD,EAAEF,IAAMG,EAAEH,GAAKE,EAAED,IAAME,EAAEF,WCpBfG,wBAWPJ,EAAGC,EAAGI,EAAGC,EAAGC,kBACjBA,GAAKA,OAGLC,KAAOR,OAGPS,IAAMR,OAGNS,MAAQL,OAGRM,OAASL,oDASEJ,EAAGC,UAEjBD,EAAEM,KAAOL,EAAEK,KAAOL,EAAEO,OAASP,EAAEK,KAAON,EAAEM,KAAON,EAAEQ,OACjDR,EAAEO,IAAMN,EAAEM,IAAMN,EAAEQ,QAAUR,EAAEM,IAAMP,EAAEO,IAAMP,EAAES,wBCnC5C,uBACQ,uBACL,+BACD,wBCDNJ,EAAK,EAEHK,wBACQC,gBACJ,OACDN,GAAKA,OACLM,QAAUA,OAKVC,WAAY,OAQZC,UAAW,gDAIXD,WAAY,OACZD,QAAQG,UAAUC,OAAOC,EAAQC,aACjCN,QAAQG,UAAUI,IAAIF,EAAQG,cAC9BR,QAAQS,gBAAgB,mDAIxBR,WAAY,OACZD,QAAQG,UAAUC,OAAOC,EAAQG,cACjCR,QAAQG,UAAUI,IAAIF,EAAQC,aAC9BN,QAAQU,aAAa,eAAe,uCAIpCC,YAAYN,EAAQO,aAAcP,EAAQG,eAC1CK,SAASd,EAAYe,IAAIC,cACzBC,MAAQjB,EAAYkB,MAAMT,aAC1BU,MAAQ,IAAIhC,qCAGRiC,gBACDC,QAAQ,SAACC,KACVrB,QAAQG,UAAUI,IAAIc,2CAIjBF,gBACJC,QAAQ,SAACC,KACVrB,QAAQG,UAAUC,OAAOiB,sCAIzBC,qBACAC,KAAKD,GAAKF,QAAQ,SAACI,KACnBxB,QAAQyB,MAAMD,GAAOF,EAAIE,4CAK3BE,eACHrB,EAAQC,OACRD,EAAQG,QACRH,EAAQO,oBAGLZ,QAAQS,gBAAgB,cACxBT,QAAU,cAInBD,EAAYe,uBAEE,eACL,OACC,aACM,wBACG,sCAIJ,aACG,kCAGK,6BAKR,qBAGG,yBACK,MAKvBf,EAAYkB,eACD,SACD,MC1GV,IAAMjB,EAAU2B,SAASC,MAAQD,SAASE,gBACpC5F,EAAI0F,SAASG,cAAc,OACjC7F,EAAEwF,MAAMM,QAAU,gDAClB/B,EAAQgC,YAAY/F,OAGdgG,EAAgB,SADJC,OAAOC,iBAAiBlG,EAAG,MAArC4D,MCQR,SAAwBuC,EACtBpC,EAASyB,OACTY,yDAASH,OAAOC,iBAAiBnC,EAAS,MAEtChB,EAAQD,EAAUsD,EAAOZ,WAGxBa,GAA4C,UAAVb,EAK3Ba,GAA4C,WAAVb,OACnC1C,EAAUsD,EAAOE,YACxBxD,EAAUsD,EAAOG,eACjBzD,EAAUsD,EAAOI,gBACjB1D,EAAUsD,EAAOK,uBARV3D,EAAUsD,EAAOM,aACxB5D,EAAUsD,EAAOO,cACjB7D,EAAUsD,EAAOQ,iBACjB9D,EAAUsD,EAAOS,kBAQd9D,EDxBTgB,EAAQ+C,YAAY9G,GEapB,IAAM+G,YAEK,KAGL,aAGK,gBAGE,MAIN,WAIP,SAAwBC,EAAOC,EAAKC,OAC5BC,EAAOC,OAAOC,UAAWN,EAAUG,GACnCI,EAAWC,MAAMC,KAAKP,GACxBQ,GAAS,SAERR,EAAI/F,OAILiG,EAAKO,UA1CX,SAAmBC,WACbC,EAAID,EAAMzG,OAEP0G,GAAG,IACH,MACC5G,EAAI6G,KAAKC,MAAMD,KAAKE,UAAYH,EAAI,IACpCI,EAAOL,EAAM3G,KACbA,GAAK2G,EAAMC,KACXA,GAAKI,SAGNL,EAgCED,CAAUT,IAKI,mBAAZE,EAAKc,KACVC,KAAK,SAAC9E,EAAGC,MAEPoE,SACK,MAGHU,EAAOhB,EAAKc,GAAG7E,EAAE+D,EAAK5B,MACtB6C,EAAOjB,EAAKc,GAAG5E,EAAE8D,EAAK5B,kBAGf8C,IAATF,QAA+BE,IAATD,MACf,EACF,GAGLD,EAAOC,GAAiB,cAATD,GAAiC,aAATC,GACjC,EAGND,EAAOC,GAAiB,aAATD,GAAgC,cAATC,EACjC,EAGF,IAEwB,mBAAjBjB,EAAKmB,WACjBJ,KAAKf,EAAKmB,SAIZb,EACKH,GAGLH,EAAKoB,WACHA,UAGCtB,OC9FT,IAAMuB,KACAC,EAAY,gBACdC,EAAQ,EAOZ,SAAgBC,EAAoBlF,WAC9B+E,EAAY/E,OACFA,GAAIM,QAAQ6E,oBAAoBH,EAAWD,EAAY/E,GAAInD,YAC3DmD,GAAM,MACX,GAMX,SAAgBoF,EAAgB9E,EAASjE,OACjC2D,EAdCgF,MADE,GAgBHnI,EAAW,SAACwI,GACZA,EAAIC,gBAAkBD,EAAIE,WACRvF,KACXqF,cAILG,iBAAiBR,EAAWnI,KAExBmD,IAAQM,UAASzD,YAEtBmD,WChCeyF,EAASvB,UACxBE,KAAKsB,IAAI3I,MAAMqH,KAAMF,GCY9B,SAAgByB,EAAcC,EAAWC,EAAaC,EAASC,OACzDC,EAAaJ,EAAYC,SAKzBzB,KAAK6B,IAAI7B,KAAK8B,MAAMF,GAAcA,GAAcD,MAErC3B,KAAK8B,MAAMF,IAInB5B,KAAK+B,IAAI/B,KAAKgC,KAAKJ,GAAaF,GASzC,SAAgBO,EAAsBC,EAAWN,EAAYF,MAExC,IAAfE,SACKM,UAyBHC,KAGGhJ,EAAI,EAAGA,GAAKuI,EAAUE,EAAYzI,MAE/Bd,KAAKgJ,EAASa,EAAUlJ,MAAMG,EAAGA,EAAIyI,YAG1CO,EAWT,SAAgBC,EAAeF,EAAWG,WCjFTvC,EDkFzBwC,GClFyBxC,EDkFFoC,ECjFtBlC,KAAK+B,IAAIpJ,MAAMqH,KAAMF,IDkFnB3G,EAAI,EAAGC,EAAM8I,EAAU7I,OAAQF,EAAIC,EAAKD,OAC3C+I,EAAU/I,IAAMmJ,EAAcD,GAAUH,EAAU/I,IAAMmJ,EAAcD,SACjElJ,SAIJ,EA0CT,SAAgBoJ,EAAqBC,EAAWC,OACxCC,OAKIpF,QAAQ,SAACqF,GACbD,EAAOC,EAAS7G,OAEX6G,EAAS7G,KAAKzD,KAAKsK,KAGnBA,EAAS7G,MAAQ6G,SAOxBC,KACEC,KACAC,mBACCrF,KAAKiF,GAAQpF,QAAQ,SAACI,OACrB8E,EAAYE,EAAOhF,KACpBrF,KAAKmK,OACJO,EAAWP,EAAUA,EAAUnJ,OAAS,GACxC2J,EAAMD,EAASlH,KAAOkH,EAAShH,MAC/BkH,EAASjD,KAAK8B,OAAOW,EAAiBO,GAAO,GAE/CE,EAAaV,EACbW,GAAU,KACVF,EAAS,EAAG,KACRG,QACIZ,EAAUa,MAAM,SAACC,OACnBC,EAAU,IAAI9H,EAAK6H,EAAEzH,KAAOoH,EAAQK,EAAExH,IAAKwH,EAAEvH,MAAOuH,EAAEtH,OAAQsH,EAAE1H,IAGhE4H,GAAaZ,EAAMa,KAAK,mBAAKhI,EAAKiI,WAAWH,EAASD,cAEnDjL,KAAKkL,GACPC,SAKMJ,OAOZD,EAAS,KACRQ,YACenB,EAAUiB,KAAK,mBAAYb,EAAMa,KAAK,SAACH,OAClDI,EAAajI,EAAKiI,WAAWf,EAAUW,UACzCI,MACiBJ,GAEdI,MAIO,KACRE,EAAWd,EAAae,UAAU,mBAASC,EAAMC,SAASJ,OACnDK,OAAOJ,EAAU,EAAGf,EAAKe,OAIlChB,EAAMqB,OAAOf,KACR7K,KAAK6K,QAOVe,OAAOtL,SAAUmK,GACxBzC,KAAK,SAAC9E,EAAGC,UAAOD,EAAEK,GAAKJ,EAAEI,KACzBsI,IAAI,mBAAY,IAAI9I,EAAMuH,EAAS9G,KAAM8G,EAAS7G,gBE5L9CqI,EAAY9I,UACZqE,MAAMC,KAAK,IAAIyE,IAAI/I,IAI5B,IAAIO,EAAK,EAEHyI,yBAQQnI,OAASmD,yIAEdA,QAAUE,OAAOC,UAAW6E,EAAQhF,QAASA,GAI9CiF,EAAKjF,QAAQkF,cACVlF,QAAQmF,UAAYF,EAAKjF,QAAQkF,aAGnCE,cACAC,MAAQL,EAAQM,YAChBC,WAAaP,EAAQM,YACrBE,WAAY,IACZC,aAAc,IACdC,eAAgB,IAChBC,kBACAC,iBAAkB,IAClBC,cAECjL,EAAKqK,EAAKa,kBAAkBjJ,OAE7BjC,QACG,IAAImL,UAAU,6DAGjBlJ,QAAUjC,IACV2B,GAAK,WAAaA,KACjB,IAEDyJ,UACAN,eAAgB,uUAvCHO,8CA2CbxB,MAAQ1L,KAAKmN,iBAEblG,QAAQmG,MAAQpN,KAAK+M,kBAAkB/M,KAAKiH,QAAQmG,YAGpDtJ,QAAQG,UAAUI,IAAI4H,EAAQ9H,QAAQkJ,WAGtCC,WAAWtN,KAAK0L,YAGhB6B,UAAYvN,KAAKwN,4BACfxE,iBAAiB,SAAUhJ,KAAKuN,WAKX,aAAxB9H,SAASgI,WAA2B,KAChCC,EAAS1N,KAAK0N,OAAOC,KAAK3N,aACzBgJ,iBAAiB,OAAQ,SAAS4E,WAChCjF,oBAAoB,OAAQiF,aAMjCC,EAAe7H,OAAOC,iBAAiBjG,KAAK8D,QAAS,MACrDuG,EAAiB4B,EAAQ6B,QAAQ9N,KAAK8D,SAASH,WAGhDoK,gBAAgBF,QAIhBG,YAAY3D,QAGZ4D,OAAOjO,KAAKiH,QAAQqF,MAAOtM,KAAKiH,QAAQiH,kBAMxCpK,QAAQqK,iBACRC,mBAAmBpO,KAAK0L,YACxB5H,QAAQyB,MAAM8I,qBAAuBrO,KAAKiH,QAAQqH,YAAWtO,KAAKiH,QAAQsH,wDASzEC,EAAiBxO,KAAKyO,cAAcd,KAAK3N,aACxCA,KAAKiH,QAAQyH,SAClB1O,KAAKiH,QAAQyH,SAASF,EAAgBxO,KAAKiH,QAAQ0H,cACnDH,4CAScI,SAGM,iBAAXA,EACF5O,KAAK8D,QAAQ+K,cAAcD,GAGzBA,GAAUA,EAAO7M,UAAgC,IAApB6M,EAAO7M,SACtC6M,EAGEA,GAAUA,EAAOE,OACnBF,EAAO,GAGT,6CAQOzI,GAEU,WAApBA,EAAO4I,gBACJjL,QAAQyB,MAAMwJ,SAAW,YAIR,WAApB5I,EAAO6I,gBACJlL,QAAQyB,MAAMyJ,SAAW,gDAa1BC,yDAAWjP,KAAKwM,WAAY0C,yDAAalP,KAAK0L,MAC9CyD,EAAMnP,KAAKoP,iBAAiBH,EAAUC,eAGvCG,qBAAqBF,QAGrB3C,WAAayC,EAIM,iBAAbA,SACJ3C,MAAQ2C,GAGRE,2CAUQF,EAAUvD,cACrB4D,KACEC,YAGFN,IAAahD,EAAQM,YACbb,IAKJxG,QAAQ,SAACsK,GACTC,EAAKC,gBAAgBT,EAAUO,EAAK1L,WAC9B7D,KAAKuP,KAENvP,KAAKuP,kEAkBJP,EAAUnL,MACA,mBAAbmL,SACFA,EAASpO,KAAKiD,EAASA,EAAS9D,UAInC2P,EAAO7L,EAAQ8L,aAAa,QAAU3D,EAAQ4D,sBAC9CxK,EAAOrF,KAAKiH,QAAQmF,UACxBuD,EAAKG,MAAM9P,KAAKiH,QAAQmF,WACxB2D,KAAKC,MAAML,YAEJM,EAAahB,UACb5J,EAAKsG,SAASsD,UAGnB3H,MAAM4I,QAAQjB,GACZjP,KAAKiH,QAAQkJ,aAAelE,EAAQmE,WAAWC,IAC1CpB,EAAS5D,KAAK4E,GAEhBhB,EAAShE,MAAMgF,GAGjB5K,EAAKsG,SAASsD,uDAQAK,IAAAA,QAASC,IAAAA,SACtBrK,QAAQ,SAACsK,KACVc,WAGApL,QAAQ,SAACsK,KACTe,4CASE7E,KACHxG,QAAQ,SAACsK,KACRgB,+CASK9E,KACNxG,QAAQ,SAACsK,KACRiB,4DASFC,aAAe1Q,KAAK2Q,oBAAoB1P,kDAU5ByK,SACS1L,KAAKiH,QAAvBqH,IAAAA,MAAOC,IAAAA,OACTqC,EAAgB5Q,KAAKiH,QAAQ4J,eAAiB,cAAgB,MAAO,QAIrEC,EAAW3J,OAAO9B,KAAKxB,EAAYe,IAAIR,OAAO2M,QAAQjF,IAAI,mBAAekF,EC5TtEC,QAAQ,WAAY,SAACC,EAAKC,aAAWA,EAAGC,kBD6T3CC,EAAaT,EAAc/E,OAAOiF,GAAUQ,SAE5CpM,QAAQ,SAACsK,KACR1L,QAAQyB,MAAMgM,mBAAqBjD,EAAQ,OAC3CxK,QAAQyB,MAAMiM,yBAA2BjD,IACzCzK,QAAQyB,MAAMkM,mBAAqBJ,0DAKnC/J,MAAMC,KAAKvH,KAAK8D,QAAQ4N,UAC5BzD,OAAO,mBAAM1M,EAAQM,EAAI8P,EAAK1K,QAAQ2K,gBACtC9F,IAAI,mBAAM,IAAIjI,EAAYhC,4CAQhB6J,OACPgG,EAAWpK,MAAMC,KAAKvH,KAAK8D,QAAQ4N,iBAClC3K,EAAO/G,KAAK0L,MAAMG,OAAOH,gBAC3B5H,UACM4N,EAASG,QAAQ/N,yDAMrB9D,KAAK0L,MAAMuC,OAAO,mBAAQuB,EAAKzL,gEAI/B/D,KAAK0L,MAAMuC,OAAO,mBAASuB,EAAKzL,mDAU1BsG,EAAgByH,OACzBC,gBAwBS,OArB2B,mBAA7B/R,KAAKiH,QAAQoC,YACfrJ,KAAKiH,QAAQoC,YAAYgB,GAGvBrK,KAAKiH,QAAQmG,MACfnB,EAAQ6B,QAAQ9N,KAAKiH,QAAQmG,OAAOzJ,MAGlC3D,KAAKiH,QAAQoC,YACfrJ,KAAKiH,QAAQoC,YAGXrJ,KAAK0L,MAAMzK,OAAS,EACtBgL,EAAQ6B,QAAQ9N,KAAK0L,MAAM,GAAG5H,SAAS,GAAMH,MAI7C0G,OAKAA,GAGF0H,EAAOD,yCASDzH,SAE2B,mBAA7BrK,KAAKiH,QAAQ+K,YACfhS,KAAKiH,QAAQ+K,YAAY3H,GACvBrK,KAAKiH,QAAQmG,MACflH,EAAelG,KAAKiH,QAAQmG,MAAO,cAEnCpN,KAAKiH,QAAQ+K,sDAWZ3H,yDAAiB4B,EAAQ6B,QAAQ9N,KAAK8D,SAASH,MACnDsO,EAASjS,KAAKkS,eAAe7H,GAC7BhB,EAAcrJ,KAAKmS,eAAe9H,EAAgB4H,GACpDG,GAAqB/H,EAAiB4H,GAAU5I,EAGhDzB,KAAK6B,IAAI7B,KAAK8B,MAAM0I,GAAqBA,GACzCpS,KAAKiH,QAAQoL,oBAEKzK,KAAK8B,MAAM0I,SAG5BE,KAAO1K,KAAKsB,IAAItB,KAAKC,MAAMuK,GAAoB,QAC/C/H,eAAiBA,OACjBkI,SAAWlJ,mDAOXvF,QAAQyB,MAAM3B,OAAS5D,KAAKwS,oBAAsB,wDAShDvJ,EAASjJ,KAAK8J,qDAQL2I,UACT7K,KAAK+B,IAAI8I,EAAQzS,KAAKiH,QAAQyL,cAAe1S,KAAKiH,QAAQ0L,oDAQzD/S,OAAMe,4DACVX,KAAK0M,gBAIJkG,QAAU5S,UACVU,KAAKd,EAAMe,6CAQZI,EAAIf,KAAKsS,cACRxI,aACE/I,MACA,OACA+I,UAAU7J,KAAK,mCAShByL,cACAmH,EAAgB7S,KAAK8S,kBAAkBpH,GAEzCjD,EAAQ,IACNvD,QAAQ,SAACsK,EAAMzO,YACVlB,MACF8E,SAASd,EAAYe,IAAIN,QAAQyO,UAKpC/P,EAAMgQ,OAAOxD,EAAKxK,MAAO6N,EAAc9R,MAAQyO,EAAKxL,kBACjDW,SAASd,EAAYe,IAAIN,QAAQyM,mBAKnC/L,MAAQ6N,EAAc9R,KACtB+D,MAAQjB,EAAYkB,MAAMT,UAC1BN,UAAW,MAIVmC,EAAS8M,EAAKC,uBAAuB1D,EAAM3L,EAAYe,IAAIN,QAAQyM,UAClEoC,gBAAkBF,EAAKG,kBAAkB3K,GAAS,OAEpDqE,OAAO7M,sCAMH,8CAWKyL,iBAGZ1L,KAAKiH,QAAQoM,WAAY,KACrBC,EAAY5H,EAAMI,IAAI,SAAC0D,EAAMzO,OAC3BwS,EAAWtH,EAAQ6B,QAAQ0B,EAAK1L,SAAS,GACzCkB,EAAQwO,EAAKC,iBAAiBF,UAC7B,IAAIlQ,EAAK2B,EAAM/B,EAAG+B,EAAM9B,EAAGqQ,EAAS5P,MAAO4P,EAAS3P,OAAQ7C,YAG9Df,KAAK0T,wBAAwBJ,EAAWtT,KAAKqK,uBAK/CqB,EAAMI,IAAI,mBAAQ0H,EAAKC,iBAAiBxH,EAAQ6B,QAAQ0B,EAAK1L,SAAS,+CAS9DyP,UF/cnB,oBACEA,IAAAA,SAAUzJ,IAAAA,UAAW6J,IAAAA,SAAUC,IAAAA,MAAOrK,IAAAA,UAAWU,IAAAA,OAE3C4J,EAAO1K,EAAcoK,EAAS5P,MAAOgQ,EAAUC,EAAOrK,GACtDuK,EAAOjK,EAAsBC,EAAW+J,EAAMD,GAC9CG,EAAmB/J,EAAe8J,EAAM7J,GAGxCjF,EAAQ,IAAIhC,EAAM2Q,EAAWI,EAAkBD,EAAKC,IAKpDC,EAAYF,EAAKC,GAAoBR,EAAS3P,OAC3C7C,EAAI,EAAGA,EAAI8S,EAAM9S,MACdgT,EAAmBhT,GAAKiT,SAG7BhP,EE8bEiP,uBAEMjU,KAAK8J,mBACN9J,KAAKuS,eACRvS,KAAKsS,eACDtS,KAAKiH,QAAQoL,uBAChBrS,KAAKiH,QAAQgD,yDAWDG,EAAWC,UAC1BF,EAAqBC,EAAWC,gDASnC5B,EAAQ,0DADOzI,KAAKkU,sBAEbhP,QAAQ,SAACsK,YACT3P,MACF8E,SAASd,EAAYe,IAAIR,OAAO2O,UASnCvD,EAAKxL,kBACFW,SAASd,EAAYe,IAAIR,OAAO2M,mBAKlCjM,MAAQjB,EAAYkB,MAAMX,SAC1BJ,UAAW,MAEVmC,EAASgO,EAAKjB,uBAAuB1D,EAAM3L,EAAYe,IAAIR,OAAO2M,UACjEoC,gBAAkBgB,EAAKf,kBAAkB3K,GAAS,OAEpDqE,OAAO7M,sCAMH,4CAUND,KAAKyM,YAAazM,KAAK0M,kBAIvB0H,wDAWgB5E,EAAM6E,OAErBlO,EAASgB,OAAOC,UAAWiN,MAE7BrU,KAAKiH,QAAQ4J,cAAe,KACxB5N,EAAIjD,KAAKiH,QAAQqN,gBAAkB1M,KAAK8B,MAAM8F,EAAKxK,MAAM/B,GAAKuM,EAAKxK,MAAM/B,EACzEC,EAAIlD,KAAKiH,QAAQqN,gBAAkB1M,KAAK8B,MAAM8F,EAAKxK,MAAM9B,GAAKsM,EAAKxK,MAAM9B,IACxEqR,uBAAyBtR,SAAQC,eAAcsM,EAAK1K,iBAEpDrB,KAAO+L,EAAKxK,MAAM/B,EAAI,OACtBS,IAAM8L,EAAKxK,MAAM9B,EAAI,YAGvBiD,8CAUWrC,EAAS0Q,EAAcC,OACnCjR,EAAKoF,EAAgB9E,EAAS,SAAC+E,SAE9B,KAAMA,UAGR+D,aAAa3M,KAAKuD,kDASF0D,qBACd,SAACuN,KACDjF,KAAK7K,SAASuC,EAAKf,UACnBuO,oBAAoBxN,EAAKsI,KAAK1L,QAASoD,EAAKrH,SAAU4U,4CAUzDzU,KAAK6M,sBACF8H,sBAGDC,EAAW5U,KAAKiH,QAAQqH,MAAQ,EAChCuG,EAAW7U,KAAK8M,OAAO7L,OAAS,EAElC4T,GAAYD,GAAY5U,KAAK2M,mBAC1BmI,kBAAkB9U,KAAK8M,QACnB+H,QACJE,kBAAkB/U,KAAK8M,aACvBkI,UAAU/I,EAAQgJ,UAAUC,cAM5BF,UAAU/I,EAAQgJ,UAAUC,aAI9BpI,OAAO7L,OAAS,4CAOLsH,mBAEXsE,iBAAkB,EbztBV,SAAkBsI,EAAKC,EAASvV,GAC1CA,IACoB,mBAAZuV,GACTvV,EAAWuV,EACXA,EAAU,MAEVvV,EAAW+C,GAIf,IAAIyS,EAAUF,GAAOA,EAAIlU,OACzB,IAAKoU,EAAS,OAAOxV,EAAS,SAE9B,IAAIyV,GAAW,EACXC,EAAU,IAAIjO,MAAM+N,GAQxB,SAASG,EAAUzU,GACjB,OAAO,SAAU0U,EAAKC,GACpB,IAAIJ,EAAJ,CAEA,GAAIG,EAGF,OAFA5V,EAAS4V,EAAKF,QACdD,GAAW,GAIbC,EAAQxU,GAAK2U,IAENL,GAASxV,EAAS,KAAM0V,KAlBnCJ,EAAIjQ,QAAQkQ,EAAU,SAAUlV,EAAIa,GAClCb,EAAGW,KAAKuU,EAASI,EAAUzU,KACzB,SAAUb,EAAIa,GAChBb,EAAGsV,EAAUzU,OaysBKwH,EAAYuD,IAAI,mBAAO6J,EAAKC,uBAAuBxQ,KAEjDpF,KAAK6V,kBAAkBlI,KAAK3N,sDAK3C4M,aAAa1H,QAAQwD,QAGrBkE,aAAa3L,OAAS,OAGtB4L,iBAAkB,4CAQPiJ,MACZA,EAAQ7U,OAAQ,KACZ8U,EAAWD,EAAQhK,IAAI,mBAAO1G,EAAIoK,KAAK1L,YAErCkS,iBAAiBD,EAAU,aACzB7Q,QAAQ,SAACE,KACXoK,KAAK7K,SAASS,EAAIe,UAClBtG,iEAOL+M,aAAa3L,OAAS,OACtB4L,iBAAkB,OAClBmI,UAAU/I,EAAQgJ,UAAUC,uCAS5BjG,EAAUgH,GACVjW,KAAKyM,cAILwC,GAAaA,GAAgC,IAApBA,EAAShO,YAC1BgL,EAAQM,gBAGhB2J,QAAQjH,QAGRkH,eAGAC,wBAGAnO,KAAKgO,uCAOPI,yDAAcrW,KAAKqM,YACjBrM,KAAKyM,gBAIL6J,iBAEC5K,EAAQ3E,EAAO/G,KAAK2Q,oBAAqB0F,QAE1CE,QAAQ7K,QAIR8K,qBAGAC,yBAEApK,SAAWgK,wCAOXK,0DACD1W,KAAKyM,YACFiK,QAEE1I,mBAIF/F,8CAUFmM,QAAO,+BAQVuC,cACIjL,EAAQK,EAAY4K,GAAU7K,IAAI,mBAAM,IAAIjI,EAAYhC,UAGzDyL,WAAW5B,QAGX4K,iBAGCM,EAAc7P,EADH/G,KAAK6W,eAAenL,GACA1L,KAAKqM,UACpCyK,EAAoB9W,KAAKkW,QAAQlW,KAAKwM,WAAYoK,GAElDG,EAAY,mBAAQrL,EAAMC,SAAS6D,IACnCwH,EAAmB,SAACxH,KACnB1K,MAAQjB,EAAYkB,MAAMX,SAC1BJ,UAAW,IACXW,SAASd,EAAYe,IAAIR,OAAO2M,UAChCpM,SAASd,EAAYe,IAAIR,OAAO2O,QAKjCF,EAAgB7S,KAAK8S,kBAAkBgE,EAAkBxH,WAC7CA,QAAQpK,QAAQ,SAACsK,EAAMzO,GACnCgW,EAAUvH,OACPxK,MAAQ6N,EAAc9R,KACVyO,KACZ7K,SAASsS,EAAK/D,uBAAuB1D,YAI5BD,OAAOrK,QAAQ,SAACsK,GAC5BuH,EAAUvH,MACKA,UAKhB1L,QAAQqK,iBAGRC,mBAAmB1C,QAGnBA,MAAQ1L,KAAK6W,eAAenL,QAG5BuC,OAAOjO,KAAKwM,mDAOZC,WAAY,uCAOZyK,kEACAzK,WAAY,EACbyK,QACG9C,wCAUF2B,iBACAA,EAAS9U,YAIRiO,EAAanD,EAAYgK,GAEzBoB,EAAWjI,EACdpD,IAAI,mBAAWsL,EAAKC,iBAAiBvT,KACrCmK,OAAO,oBAAUuB,SAcfH,wCAEK8H,SAGLhB,QAAQgB,QAERlP,YAIAyD,MAAQ1L,KAAK0L,MAAMuC,OAAO,mBAASkJ,EAASxL,SAAS6D,UACrD4G,wBAEAjW,KAAK8L,EAAQgJ,UAAUC,OA1BP,aACdoC,cAAcH,KAGRjS,QAAQ,SAACpB,KACV7B,WAAW4E,YAAY/C,OAG5BkR,UAAU/I,EAAQgJ,UAAUsC,SAAWrI,2DA0B/BpL,UACR9D,KAAK0L,MAAM8L,KAAK,mBAAQhI,EAAK1L,UAAYA,yDAS3CwT,cAActX,KAAK0L,YACnBiB,eAAgB,OAGhBjB,MAAQ1L,KAAKmN,iBAGbG,WAAWtN,KAAK0L,YAEhBvL,KAAK8L,EAAQgJ,UAAUC,OAAQ,aAE7B9G,mBAAmBqJ,EAAK/L,SACxBiB,eAAgB,SAIlBsB,OAAOjO,KAAKwM,mDAOZmI,yBACEhM,oBAAoB,SAAU3I,KAAKuN,gBAGrCzJ,QAAQG,UAAUC,OAAO,gBACzBJ,QAAQS,gBAAgB,cAGxB+S,cAActX,KAAK0L,YAEnBA,MAAMzK,OAAS,OACf2L,aAAa3L,OAAS,OAGtBgG,QAAQmG,MAAQ,UAChBtJ,QAAU,UAIV4I,aAAc,OACdD,WAAY,oCAyBJ3I,OAAS4T,0DAEhBvR,EAASH,OAAOC,iBAAiBnC,EAAS,MAC5CH,EAAQuC,EAAepC,EAAS,QAASqC,GACzCvC,EAASsC,EAAepC,EAAS,SAAUqC,GAE3CuR,OACiBxR,EAAepC,EAAS,aAAcqC,GACrCD,EAAepC,EAAS,cAAeqC,MACzCD,EAAepC,EAAS,YAAaqC,GAClCD,EAAepC,EAAS,eAAgBqC,sEAkBzC4P,EAAUlW,OAI1Bc,EAAOoV,EAASjK,IAAI,SAAChI,OACjByB,EAAUzB,EAAVyB,MACFoS,EAAWpS,EAAMgM,mBACjBqG,EAAQrS,EAAM4N,yBAGd5B,mBATK,QAUL4B,gBAVK,mCAqBJ,GAAGhF,cAGHjJ,QAAQ,SAACpB,EAAS/C,KACjBwE,MAAMgM,mBAAqB5Q,EAAKI,GAAG4W,WACnCpS,MAAM4N,gBAAkBxS,EAAKI,GAAG6W,wBAK9C3L,EAAQpI,YAAcA,EAEtBoI,EAAQM,UAAY,MACpBN,EAAQ4D,qBAAuB,SAG/B5D,EAAQgJ,kBACE,yBACC,mBAIXhJ,EAAQ9H,QAAUA,EAGlB8H,EAAQmE,gBACD,UACA,OAIPnE,EAAQhF,eAECgF,EAAQM,gBAGR,WAGC,8CAGM,UAIP,iBAIM,cAIA,YAIF,YAIH,kBAIS,gBAIJ,6BAOC,kBAGC,oBAGG,mBAGH,aAKHN,EAAQmE,WAAWC,gBAGnB,mBAIK,GAGnBpE,EAAQjJ,MAAQA,EAChBiJ,EAAQ5I,KAAOA,EAGf4I,EAAQ4L,SAAW9Q,EACnBkF,EAAQ6L,gBAAkB3O,EAC1B8C,EAAQ8L,wBAA0BlO,EAClCoC,EAAQ+L,iBAAmBhO,EAC3BiC,EAAQgM,uBAAyB9N"} \ No newline at end of file +{"version":3,"file":"shuffle.min.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/layout.js","../src/array-min.js","../src/shuffle.js","../src/hyphenate.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n"],"names":["E","prototype","on","name","callback","ctx","e","this","push","fn","once","self","listener","off","apply","arguments","_","emit","data","slice","call","evtArr","i","len","length","evts","liveEvents","proto","Element","vendor","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","el","selector","nodeType","nodes","parentNode","querySelectorAll","func","wait","args","rtn","timeoutID","last","delta","Date","setTimeout","noop","getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","createElement","cssText","appendChild","ret","window","getComputedStyle","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","removeChild","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","randomize","array","n","Math","floor","random","temp","by","sort","valA","valB","undefined","compare","reverse","transitions","eventName","count","cancelTransitionEnd","removeEventListener","onTransitionEnd","evt","currentTarget","target","addEventListener","arrayMax","max","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","min","ceil","getAvailablePositions","positions","available","getShortColumn","buffer","minPosition","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","rowIndex","findIndex","items","includes","splice","concat","map","arrayUnique","Set","Shuffle","_this","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","_getElementOption","TypeError","_init","TinyEmitter","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_this2","_doesPassFilter","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","before","k","replace","str","m1","toLowerCase","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","_this3","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","shuffle","itemPositions","_getNextPositions","after","equals","_this4","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","itemSize","_this5","_getItemPosition","getTransformedPositions","gridSize","total","span","setY","shortColumnIndex","setHeight","getItemPosition","_getConcealedItems","_this6","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","fns","context","pending","finished","results","maybeDone","err","result","_this8","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","sortedItems","_mergeNewItems","allSortedItemsSet","isNewItem","applyHiddenState","_this9","isUpdateLayout","oldItems","_this10","getItemByElement","_disposeItems","REMOVED","find","_this11","includeMargins","duration","delay","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file diff --git a/docs/dist/shuffle.js b/docs/dist/shuffle.js index ab31fdf..97f222b 100644 --- a/docs/dist/shuffle.js +++ b/docs/dist/shuffle.js @@ -1,2274 +1,2255 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.Shuffle = factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Shuffle = factory()); }(this, (function () { 'use strict'; -function E () { - // Keep this empty so it's easier to inherit from - // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) -} - -E.prototype = { - on: function (name, callback, ctx) { - var e = this.e || (this.e = {}); + function E () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) + } - (e[name] || (e[name] = [])).push({ - fn: callback, - ctx: ctx - }); + E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); - return this; - }, + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx + }); - once: function (name, callback, ctx) { - var self = this; - function listener () { - self.off(name, listener); - callback.apply(ctx, arguments); - } + return this; + }, - listener._ = callback; - return this.on(name, listener, ctx); - }, + once: function (name, callback, ctx) { + var self = this; + function listener () { + self.off(name, listener); + callback.apply(ctx, arguments); + } + listener._ = callback; + return this.on(name, listener, ctx); + }, - emit: function (name) { - var data = [].slice.call(arguments, 1); - var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); - var i = 0; - var len = evtArr.length; + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; - for (i; i < len; i++) { - evtArr[i].fn.apply(evtArr[i].ctx, data); - } + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } - return this; - }, + return this; + }, - off: function (name, callback) { - var e = this.e || (this.e = {}); - var evts = e[name]; - var liveEvents = []; + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; - if (evts && callback) { - for (var i = 0, len = evts.length; i < len; i++) { - if (evts[i].fn !== callback && evts[i].fn._ !== callback) - liveEvents.push(evts[i]); + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); + } } - } - // Remove event from queue to prevent memory leak - // Suggested by https://github.com/lazd - // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 - (liveEvents.length) - ? e[name] = liveEvents - : delete e[name]; - - return this; - } -}; - -var tinyEmitter = E; - -var proto = typeof Element !== 'undefined' ? Element.prototype : {}; -var vendor = proto.matches - || proto.matchesSelector - || proto.webkitMatchesSelector - || proto.mozMatchesSelector - || proto.msMatchesSelector - || proto.oMatchesSelector; - -var matchesSelector = match; - -/** - * Match `el` to `selector`. - * - * @param {Element} el - * @param {String} selector - * @return {Boolean} - * @api public - */ - -function match(el, selector) { - if (!el || el.nodeType !== 1) return false; - if (vendor) return vendor.call(el, selector); - var nodes = el.parentNode.querySelectorAll(selector); - for (var i = 0; i < nodes.length; i++) { - if (nodes[i] == el) return true; - } - return false; -} - -var throttleit = throttle; - -/** - * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds. - * - * @param {Function} func Function to wrap. - * @param {Number} wait Number of milliseconds that must elapse between `func` invocations. - * @return {Function} A new function that wraps the `func` function passed in. - */ - -function throttle (func, wait) { - var ctx, args, rtn, timeoutID; // caching - var last = 0; - - return function throttled () { - ctx = this; - args = arguments; - var delta = new Date() - last; - if (!timeoutID) - if (delta >= wait) call(); - else timeoutID = setTimeout(call, wait - delta); - return rtn; - }; + (liveEvents.length) + ? e[name] = liveEvents + : delete e[name]; - function call () { - timeoutID = 0; - last = +new Date(); - rtn = func.apply(ctx, args); - ctx = null; - args = null; - } -} - -var arrayParallel = function parallel(fns, context, callback) { - if (!callback) { - if (typeof context === 'function') { - callback = context; - context = null; - } else { - callback = noop; + return this; } - } - - var pending = fns && fns.length; - if (!pending) return callback(null, []); - - var finished = false; - var results = new Array(pending); + }; - fns.forEach(context ? function (fn, i) { - fn.call(context, maybeDone(i)); - } : function (fn, i) { - fn(maybeDone(i)); - }); + var tinyEmitter = E; - function maybeDone(i) { - return function (err, result) { - if (finished) return; + var proto = typeof Element !== 'undefined' ? Element.prototype : {}; + var vendor = proto.matches + || proto.matchesSelector + || proto.webkitMatchesSelector + || proto.mozMatchesSelector + || proto.msMatchesSelector + || proto.oMatchesSelector; - if (err) { - callback(err, results); - finished = true; - return - } + var matchesSelector = match; - results[i] = result; + /** + * Match `el` to `selector`. + * + * @param {Element} el + * @param {String} selector + * @return {Boolean} + * @api public + */ - if (!--pending) callback(null, results); - } - } -}; - -function noop() {} - -/** - * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`. - * @param {*} value Possibly numeric value. - * @return {number} `value` or zero if `value` isn't numeric. - */ -function getNumber(value) { - return parseFloat(value) || 0; -} - -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); + function match(el, selector) { + if (!el || el.nodeType !== 1) return false; + if (vendor) return vendor.call(el, selector); + var nodes = el.parentNode.querySelectorAll(selector); + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] == el) return true; } + return false; } - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - - - - - - - + var throttleit = throttle; + /** + * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds. + * + * @param {Function} func Function to wrap. + * @param {Number} wait Number of milliseconds that must elapse between `func` invocations. + * @return {Function} A new function that wraps the `func` function passed in. + */ -var inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + function throttle (func, wait) { + var ctx, args, rtn, timeoutID; // caching + var last = 0; + + return function throttled () { + ctx = this; + args = arguments; + var delta = new Date() - last; + if (!timeoutID) + if (delta >= wait) call(); + else timeoutID = setTimeout(call, wait - delta); + return rtn; + }; + + function call () { + timeoutID = 0; + last = +new Date(); + rtn = func.apply(ctx, args); + ctx = null; + args = null; + } } - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true + var arrayParallel = function parallel(fns, context, callback) { + if (!callback) { + if (typeof context === 'function') { + callback = context; + context = null; + } else { + callback = noop; + } } - }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; -}; - - - - + var pending = fns && fns.length; + if (!pending) return callback(null, []); + var finished = false; + var results = new Array(pending); + fns.forEach(context ? function (fn, i) { + fn.call(context, maybeDone(i)); + } : function (fn, i) { + fn(maybeDone(i)); + }); + function maybeDone(i) { + return function (err, result) { + if (finished) return; + if (err) { + callback(err, results); + finished = true; + return + } + results[i] = result; -var possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } + if (!--pending) callback(null, results); + } + } + }; - return call && (typeof call === "object" || typeof call === "function") ? call : self; -}; + function noop() {} -var Point = function () { /** - * Represents a coordinate pair. - * @param {number} [x=0] X. - * @param {number} [y=0] Y. + * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`. + * @param {*} value Possibly numeric value. + * @return {number} `value` or zero if `value` isn't numeric. */ - function Point(x, y) { - classCallCheck(this, Point); - - this.x = getNumber(x); - this.y = getNumber(y); + function getNumber(value) { + return parseFloat(value) || 0; } - /** - * Whether two points are equal. - * @param {Point} a Point A. - * @param {Point} b Point B. - * @return {boolean} - */ - - - createClass(Point, null, [{ - key: 'equals', - value: function equals(a, b) { - return a.x === b.x && a.y === b.y; + var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); } - }]); - return Point; -}(); - -var Rect = function () { - /** - * Class for representing rectangular regions. - * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js - * @param {number} x Left. - * @param {number} y Top. - * @param {number} w Width. - * @param {number} h Height. - * @param {number} id Identifier - * @constructor - */ - function Rect(x, y, w, h, id) { - classCallCheck(this, Rect); - - this.id = id; - - /** @type {number} */ - this.left = x; - - /** @type {number} */ - this.top = y; - - /** @type {number} */ - this.width = w; - - /** @type {number} */ - this.height = h; - } + }; - /** - * Returns whether two rectangles intersect. - * @param {Rect} a A Rectangle. - * @param {Rect} b A Rectangle. - * @return {boolean} Whether a and b intersect. - */ + var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); - createClass(Rect, null, [{ - key: "intersects", - value: function intersects(a, b) { - return a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height; + var inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } - }]); - return Rect; -}(); -var Classes = { - BASE: 'shuffle', - SHUFFLE_ITEM: 'shuffle-item', - VISIBLE: 'shuffle-item--visible', - HIDDEN: 'shuffle-item--hidden' -}; - -var id = 0; + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; -var ShuffleItem = function () { - function ShuffleItem(element) { - classCallCheck(this, ShuffleItem); + var possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } - id += 1; - this.id = id; - this.element = element; + return call && (typeof call === "object" || typeof call === "function") ? call : self; + }; + var Point = function () { /** - * Used to separate items for layout and shrink. + * Represents a coordinate pair. + * @param {number} [x=0] X. + * @param {number} [y=0] Y. */ - this.isVisible = true; + function Point(x, y) { + classCallCheck(this, Point); + + this.x = getNumber(x); + this.y = getNumber(y); + } /** - * Used to determine if a transition will happen. By the time the _layout - * and _shrink methods get the ShuffleItem instances, the `isVisible` value - * has already been changed by the separation methods, so this property is - * needed to know if the item was visible/hidden before the shrink/layout. + * Whether two points are equal. + * @param {Point} a Point A. + * @param {Point} b Point B. + * @return {boolean} */ - this.isHidden = false; - } - createClass(ShuffleItem, [{ - key: 'show', - value: function show() { - this.isVisible = true; - this.element.classList.remove(Classes.HIDDEN); - this.element.classList.add(Classes.VISIBLE); - this.element.removeAttribute('aria-hidden'); - } - }, { - key: 'hide', - value: function hide() { - this.isVisible = false; - this.element.classList.remove(Classes.VISIBLE); - this.element.classList.add(Classes.HIDDEN); - this.element.setAttribute('aria-hidden', true); - } - }, { - key: 'init', - value: function init() { - this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]); - this.applyCss(ShuffleItem.Css.INITIAL); - this.scale = ShuffleItem.Scale.VISIBLE; - this.point = new Point(); - } - }, { - key: 'addClasses', - value: function addClasses(classes) { - var _this = this; - classes.forEach(function (className) { - _this.element.classList.add(className); - }); - } - }, { - key: 'removeClasses', - value: function removeClasses(classes) { - var _this2 = this; + createClass(Point, null, [{ + key: 'equals', + value: function equals(a, b) { + return a.x === b.x && a.y === b.y; + } + }]); + return Point; + }(); - classes.forEach(function (className) { - _this2.element.classList.remove(className); - }); - } - }, { - key: 'applyCss', - value: function applyCss(obj) { - var _this3 = this; + var Rect = function () { + /** + * Class for representing rectangular regions. + * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js + * @param {number} x Left. + * @param {number} y Top. + * @param {number} w Width. + * @param {number} h Height. + * @param {number} id Identifier + * @constructor + */ + function Rect(x, y, w, h, id) { + classCallCheck(this, Rect); - Object.keys(obj).forEach(function (key) { - _this3.element.style[key] = obj[key]; - }); - } - }, { - key: 'dispose', - value: function dispose() { - this.removeClasses([Classes.HIDDEN, Classes.VISIBLE, Classes.SHUFFLE_ITEM]); + this.id = id; - this.element.removeAttribute('style'); - this.element = null; - } - }]); - return ShuffleItem; -}(); - -ShuffleItem.Css = { - INITIAL: { - position: 'absolute', - top: 0, - left: 0, - visibility: 'visible', - 'will-change': 'transform' - }, - VISIBLE: { - before: { - opacity: 1, - visibility: 'visible' - }, - after: { - transitionDelay: '' - } - }, - HIDDEN: { - before: { - opacity: 0 - }, - after: { - visibility: 'hidden', - transitionDelay: '' - } - } -}; - -ShuffleItem.Scale = { - VISIBLE: 1, - HIDDEN: 0.001 -}; - -var element = document.body || document.documentElement; -var e = document.createElement('div'); -e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; -element.appendChild(e); - -var _window$getComputedSt = window.getComputedStyle(e, null); -var width = _window$getComputedSt.width; - -var ret = width === '10px'; - -element.removeChild(e); - -/** - * Retrieve the computed style for an element, parsed as a float. - * @param {Element} element Element to get style for. - * @param {string} style Style property. - * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to - * use instead of asking for them again. - * @return {number} The parsed computed value or zero if that fails because IE - * will return 'auto' when the element doesn't have margins instead of - * the computed style. - */ -function getNumberStyle(element, style) { - var styles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window.getComputedStyle(element, null); - - var value = getNumber(styles[style]); - - // Support IE<=11 and W3C spec. - if (!ret && style === 'width') { - value += getNumber(styles.paddingLeft) + getNumber(styles.paddingRight) + getNumber(styles.borderLeftWidth) + getNumber(styles.borderRightWidth); - } else if (!ret && style === 'height') { - value += getNumber(styles.paddingTop) + getNumber(styles.paddingBottom) + getNumber(styles.borderTopWidth) + getNumber(styles.borderBottomWidth); - } + /** @type {number} */ + this.left = x; - return value; -} - -/** - * Fisher-Yates shuffle. - * http://stackoverflow.com/a/962890/373422 - * https://bost.ocks.org/mike/shuffle/ - * @param {Array} array Array to shuffle. - * @return {Array} Randomly sorted array. - */ -function randomize(array) { - var n = array.length; - - while (n) { - n -= 1; - var i = Math.floor(Math.random() * (n + 1)); - var temp = array[i]; - array[i] = array[n]; - array[n] = temp; - } + /** @type {number} */ + this.top = y; - return array; -} + /** @type {number} */ + this.width = w; -var defaults$1 = { - // Use array.reverse() to reverse the results - reverse: false, + /** @type {number} */ + this.height = h; + } - // Sorting function - by: null, + /** + * Returns whether two rectangles intersect. + * @param {Rect} a A Rectangle. + * @param {Rect} b A Rectangle. + * @return {boolean} Whether a and b intersect. + */ - // Custom sort function - compare: null, - // If true, this will skip the sorting and return a randomized order in the array - randomize: false, + createClass(Rect, null, [{ + key: "intersects", + value: function intersects(a, b) { + return a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height; + } + }]); + return Rect; + }(); + + var Classes = { + BASE: 'shuffle', + SHUFFLE_ITEM: 'shuffle-item', + VISIBLE: 'shuffle-item--visible', + HIDDEN: 'shuffle-item--hidden' + }; - // Determines which property of each item in the array is passed to the - // sorting method. - key: 'element' -}; + var id = 0; -// You can return `undefined` from the `by` function to revert to DOM order. -function sorter(arr, options) { - var opts = Object.assign({}, defaults$1, options); - var original = Array.from(arr); - var revert = false; + var ShuffleItem = function () { + function ShuffleItem(element) { + classCallCheck(this, ShuffleItem); - if (!arr.length) { - return []; - } + id += 1; + this.id = id; + this.element = element; - if (opts.randomize) { - return randomize(arr); - } + /** + * Used to separate items for layout and shrink. + */ + this.isVisible = true; - // Sort the elements by the opts.by function. - // If we don't have opts.by, default to DOM order - if (typeof opts.by === 'function') { - arr.sort(function (a, b) { - // Exit early if we already know we want to revert - if (revert) { - return 0; + /** + * Used to determine if a transition will happen. By the time the _layout + * and _shrink methods get the ShuffleItem instances, the `isVisible` value + * has already been changed by the separation methods, so this property is + * needed to know if the item was visible/hidden before the shrink/layout. + */ + this.isHidden = false; + } + + createClass(ShuffleItem, [{ + key: 'show', + value: function show() { + this.isVisible = true; + this.element.classList.remove(Classes.HIDDEN); + this.element.classList.add(Classes.VISIBLE); + this.element.removeAttribute('aria-hidden'); } - - var valA = opts.by(a[opts.key]); - var valB = opts.by(b[opts.key]); - - // If both values are undefined, use the DOM order - if (valA === undefined && valB === undefined) { - revert = true; - return 0; + }, { + key: 'hide', + value: function hide() { + this.isVisible = false; + this.element.classList.remove(Classes.VISIBLE); + this.element.classList.add(Classes.HIDDEN); + this.element.setAttribute('aria-hidden', true); } - - if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') { - return -1; + }, { + key: 'init', + value: function init() { + this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]); + this.applyCss(ShuffleItem.Css.INITIAL); + this.scale = ShuffleItem.Scale.VISIBLE; + this.point = new Point(); } + }, { + key: 'addClasses', + value: function addClasses(classes) { + var _this = this; - if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') { - return 1; + classes.forEach(function (className) { + _this.element.classList.add(className); + }); } + }, { + key: 'removeClasses', + value: function removeClasses(classes) { + var _this2 = this; - return 0; - }); - } else if (typeof opts.compare === 'function') { - arr.sort(opts.compare); - } - - // Revert to the original array if necessary - if (revert) { - return original; - } - - if (opts.reverse) { - arr.reverse(); - } - - return arr; -} - -var transitions = {}; -var eventName = 'transitionend'; -var count = 0; - -function uniqueId() { - count += 1; - return eventName + count; -} - -function cancelTransitionEnd(id) { - if (transitions[id]) { - transitions[id].element.removeEventListener(eventName, transitions[id].listener); - transitions[id] = null; - return true; - } + classes.forEach(function (className) { + _this2.element.classList.remove(className); + }); + } + }, { + key: 'applyCss', + value: function applyCss(obj) { + var _this3 = this; - return false; -} + Object.keys(obj).forEach(function (key) { + _this3.element.style[key] = obj[key]; + }); + } + }, { + key: 'dispose', + value: function dispose() { + this.removeClasses([Classes.HIDDEN, Classes.VISIBLE, Classes.SHUFFLE_ITEM]); -function onTransitionEnd(element, callback) { - var id = uniqueId(); - var listener = function listener(evt) { - if (evt.currentTarget === evt.target) { - cancelTransitionEnd(id); - callback(evt); + this.element.removeAttribute('style'); + this.element = null; + } + }]); + return ShuffleItem; + }(); + + ShuffleItem.Css = { + INITIAL: { + position: 'absolute', + top: 0, + left: 0, + visibility: 'visible', + 'will-change': 'transform' + }, + VISIBLE: { + before: { + opacity: 1, + visibility: 'visible' + }, + after: { + transitionDelay: '' + } + }, + HIDDEN: { + before: { + opacity: 0 + }, + after: { + visibility: 'hidden', + transitionDelay: '' + } } }; - element.addEventListener(eventName, listener); - - transitions[id] = { element: element, listener: listener }; - - return id; -} - -function arrayMax(array) { - return Math.max.apply(Math, array); // eslint-disable-line prefer-spread -} - -function arrayMin(array) { - return Math.min.apply(Math, array); // eslint-disable-line prefer-spread -} - -/** - * Determine the number of columns an items spans. - * @param {number} itemWidth Width of the item. - * @param {number} columnWidth Width of the column (includes gutter). - * @param {number} columns Total number of columns - * @param {number} threshold A buffer value for the size of the column to fit. - * @return {number} - */ -function getColumnSpan(itemWidth, columnWidth, columns, threshold) { - var columnSpan = itemWidth / columnWidth; - - // If the difference between the rounded column span number and the - // calculated column span number is really small, round the number to - // make it fit. - if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) { - // e.g. columnSpan = 4.0089945390298745 - columnSpan = Math.round(columnSpan); - } - - // Ensure the column span is not more than the amount of columns in the whole layout. - return Math.min(Math.ceil(columnSpan), columns); -} - -/** - * Retrieves the column set to use for placement. - * @param {number} columnSpan The number of columns this current item spans. - * @param {number} columns The total columns in the grid. - * @return {Array.} An array of numbers represeting the column set. - */ -function getAvailablePositions(positions, columnSpan, columns) { - // The item spans only one column. - if (columnSpan === 1) { - return positions; - } + ShuffleItem.Scale = { + VISIBLE: 1, + HIDDEN: 0.001 + }; - // The item spans more than one column, figure out how many different - // places it could fit horizontally. - // The group count is the number of places within the positions this block - // could fit, ignoring the current positions of items. - // Imagine a 2 column brick as the second item in a 4 column grid with - // 10px height each. Find the places it would fit: - // [20, 10, 10, 0] - // | | | - // * * * - // - // Then take the places which fit and get the bigger of the two: - // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10] - // - // Next, find the first smallest number (the short column). - // [20, 10, 10] - // | - // * - // - // And that's where it should be placed! - // - // Another example where the second column's item extends past the first: - // [10, 20, 10, 0] => [20, 20, 10] => 10 - var available = []; - - // For how many possible positions for this item there are. - for (var i = 0; i <= columns - columnSpan; i++) { - // Find the bigger value for each place it could fit. - available.push(arrayMax(positions.slice(i, i + columnSpan))); - } + var element = document.body || document.documentElement; + var e = document.createElement('div'); + e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; + element.appendChild(e); - return available; -} - -/** - * Find index of short column, the first from the left where this item will go. - * - * @param {Array.} positions The array to search for the smallest number. - * @param {number} buffer Optional buffer which is very useful when the height - * is a percentage of the width. - * @return {number} Index of the short column. - */ -function getShortColumn(positions, buffer) { - var minPosition = arrayMin(positions); - for (var i = 0, len = positions.length; i < len; i++) { - if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) { - return i; - } - } + var _window$getComputedSt = window.getComputedStyle(e, null), + width = _window$getComputedSt.width; - return 0; -} - -/** - * Determine the location of the next item, based on its size. - * @param {Object} itemSize Object with width and height. - * @param {Array.} positions Positions of the other current items. - * @param {number} gridSize The column width or row height. - * @param {number} total The total number of columns or rows. - * @param {number} threshold Buffer value for the column to fit. - * @param {number} buffer Vertical buffer for the height of items. - * @return {Point} - */ -function getItemPosition(_ref) { - var itemSize = _ref.itemSize, - positions = _ref.positions, - gridSize = _ref.gridSize, - total = _ref.total, - threshold = _ref.threshold, - buffer = _ref.buffer; - - var span = getColumnSpan(itemSize.width, gridSize, total, threshold); - var setY = getAvailablePositions(positions, span, total); - var shortColumnIndex = getShortColumn(setY, buffer); - - // Position the item - var point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]); - - // Update the columns array with the new values for each column. - // e.g. before the update the columns could be [250, 0, 0, 0] for an item - // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0]. - var setHeight = setY[shortColumnIndex] + itemSize.height; - for (var i = 0; i < span; i++) { - positions[shortColumnIndex + i] = setHeight; - } + var ret = width === '10px'; - return point; -} - -/** - * This method attempts to center items. This method could potentially be slow - * with a large number of items because it must place items, then check every - * previous item to ensure there is no overlap. - * @param {Array.} itemRects Item data objects. - * @param {number} containerWidth Width of the containing element. - * @return {Array.} - */ -function getCenteredPositions(itemRects, containerWidth) { - var rowMap = {}; - - // Populate rows by their offset because items could jump between rows like: - // a c - // bbb - itemRects.forEach(function (itemRect) { - if (rowMap[itemRect.top]) { - // Push the point to the last row array. - rowMap[itemRect.top].push(itemRect); - } else { - // Start of a new row. - rowMap[itemRect.top] = [itemRect]; - } - }); - - // For each row, find the end of the last item, then calculate - // the remaining space by dividing it by 2. Then add that - // offset to the x position of each point. - var rects = []; - var rows = []; - var centeredRows = []; - Object.keys(rowMap).forEach(function (key) { - var itemRects = rowMap[key]; - rows.push(itemRects); - var lastItem = itemRects[itemRects.length - 1]; - var end = lastItem.left + lastItem.width; - var offset = Math.round((containerWidth - end) / 2); - - var finalRects = itemRects; - var canMove = false; - if (offset > 0) { - var newRects = []; - canMove = itemRects.every(function (r) { - var newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id); - - // Check all current rects to make sure none overlap. - var noOverlap = !rects.some(function (r) { - return Rect.intersects(newRect, r); - }); + element.removeChild(e); - newRects.push(newRect); - return noOverlap; - }); - - // If none of the rectangles overlapped, the whole group can be centered. - if (canMove) { - finalRects = newRects; - } - } + /** + * Retrieve the computed style for an element, parsed as a float. + * @param {Element} element Element to get style for. + * @param {string} style Style property. + * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to + * use instead of asking for them again. + * @return {number} The parsed computed value or zero if that fails because IE + * will return 'auto' when the element doesn't have margins instead of + * the computed style. + */ + function getNumberStyle(element, style) { + var styles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window.getComputedStyle(element, null); - // If the items are not going to be offset, ensure that the original - // placement for this row will not overlap previous rows (row-spanning - // elements could be in the way). - if (!canMove) { - var intersectingRect = void 0; - var hasOverlap = itemRects.some(function (itemRect) { - return rects.some(function (r) { - var intersects = Rect.intersects(itemRect, r); - if (intersects) { - intersectingRect = r; - } - return intersects; - }); - }); + var value = getNumber(styles[style]); - // If there is any overlap, replace the overlapping row with the original. - if (hasOverlap) { - var rowIndex = centeredRows.findIndex(function (items) { - return items.includes(intersectingRect); - }); - centeredRows.splice(rowIndex, 1, rows[rowIndex]); - } + // Support IE<=11 and W3C spec. + if (!ret && style === 'width') { + value += getNumber(styles.paddingLeft) + getNumber(styles.paddingRight) + getNumber(styles.borderLeftWidth) + getNumber(styles.borderRightWidth); + } else if (!ret && style === 'height') { + value += getNumber(styles.paddingTop) + getNumber(styles.paddingBottom) + getNumber(styles.borderTopWidth) + getNumber(styles.borderBottomWidth); } - rects = rects.concat(finalRects); - centeredRows.push(finalRects); - }); - - // Reduce array of arrays to a single array of points. - // https://stackoverflow.com/a/10865042/373422 - // Then reset sort back to how the items were passed to this method. - // Remove the wrapper object with index, map to a Point. - return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread - .sort(function (a, b) { - return a.id - b.id; - }).map(function (itemRect) { - return new Point(itemRect.left, itemRect.top); - }); -} - -/** - * Hyphenates a javascript style string to a css one. For example: - * MozBoxSizing -> -moz-box-sizing. - * @param {string} str The string to hyphenate. - * @return {string} The hyphenated string. - */ -function hyphenate(str) { - return str.replace(/([A-Z])/g, function (str, m1) { - return "-" + m1.toLowerCase(); - }); -} - -function arrayUnique(x) { - return Array.from(new Set(x)); -} - -// Used for unique instance variables -var id$1 = 0; - -var Shuffle = function (_TinyEmitter) { - inherits(Shuffle, _TinyEmitter); + return value; + } /** - * Categorize, sort, and filter a responsive grid of items. - * - * @param {Element} element An element which is the parent container for the grid items. - * @param {Object} [options=Shuffle.options] Options object. - * @constructor + * Fisher-Yates shuffle. + * http://stackoverflow.com/a/962890/373422 + * https://bost.ocks.org/mike/shuffle/ + * @param {Array} array Array to shuffle. + * @return {Array} Randomly sorted array. */ - function Shuffle(element) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - classCallCheck(this, Shuffle); - - var _this = possibleConstructorReturn(this, (Shuffle.__proto__ || Object.getPrototypeOf(Shuffle)).call(this)); + function randomize(array) { + var n = array.length; - _this.options = Object.assign({}, Shuffle.options, options); - - // Allow misspelling of delimiter since that's how it used to be. - // Remove in v6. - if (_this.options.delimeter) { - _this.options.delimiter = _this.options.delimeter; + while (n) { + n -= 1; + var i = Math.floor(Math.random() * (n + 1)); + var temp = array[i]; + array[i] = array[n]; + array[n] = temp; } - _this.lastSort = {}; - _this.group = Shuffle.ALL_ITEMS; - _this.lastFilter = Shuffle.ALL_ITEMS; - _this.isEnabled = true; - _this.isDestroyed = false; - _this.isInitialized = false; - _this._transitions = []; - _this.isTransitioning = false; - _this._queue = []; + return array; + } - var el = _this._getElementOption(element); + var defaults$1 = { + // Use array.reverse() to reverse the results + reverse: false, - if (!el) { - throw new TypeError('Shuffle needs to be initialized with an element.'); - } + // Sorting function + by: null, - _this.element = el; - _this.id = 'shuffle_' + id$1; - id$1 += 1; - - _this._init(); - _this.isInitialized = true; - return _this; - } + // Custom sort function + compare: null, - createClass(Shuffle, [{ - key: '_init', - value: function _init() { - this.items = this._getItems(); + // If true, this will skip the sorting and return a randomized order in the array + randomize: false, - this.options.sizer = this._getElementOption(this.options.sizer); + // Determines which property of each item in the array is passed to the + // sorting method. + key: 'element' + }; - // Add class and invalidate styles - this.element.classList.add(Shuffle.Classes.BASE); + // You can return `undefined` from the `by` function to revert to DOM order. + function sorter(arr, options) { + var opts = Object.assign({}, defaults$1, options); + var original = Array.from(arr); + var revert = false; - // Set initial css for each item - this._initItems(this.items); + if (!arr.length) { + return []; + } - // Bind resize events - this._onResize = this._getResizeFunction(); - window.addEventListener('resize', this._onResize); + if (opts.randomize) { + return randomize(arr); + } - // If the page has not already emitted the `load` event, call layout on load. - // This avoids layout issues caused by images and fonts loading after the - // instance has been initialized. - if (document.readyState !== 'complete') { - var layout = this.layout.bind(this); - window.addEventListener('load', function onLoad() { - window.removeEventListener('load', onLoad); - layout(); - }); - } + // Sort the elements by the opts.by function. + // If we don't have opts.by, default to DOM order + if (typeof opts.by === 'function') { + arr.sort(function (a, b) { + // Exit early if we already know we want to revert + if (revert) { + return 0; + } - // Get container css all in one request. Causes reflow - var containerCss = window.getComputedStyle(this.element, null); - var containerWidth = Shuffle.getSize(this.element).width; + var valA = opts.by(a[opts.key]); + var valB = opts.by(b[opts.key]); - // Add styles to the container if it doesn't have them. - this._validateStyles(containerCss); + // If both values are undefined, use the DOM order + if (valA === undefined && valB === undefined) { + revert = true; + return 0; + } - // We already got the container's width above, no need to cause another - // reflow getting it again... Calculate the number of columns there will be - this._setColumns(containerWidth); + if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') { + return -1; + } - // Kick off! - this.filter(this.options.group, this.options.initialSort); + if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') { + return 1; + } - // The shuffle items haven't had transitions set on them yet so the user - // doesn't see the first layout. Set them now that the first layout is done. - // First, however, a synchronous layout must be caused for the previous - // styles to be applied without transitions. - this.element.offsetWidth; // eslint-disable-line no-unused-expressions - this.setItemTransitions(this.items); - this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing; + return 0; + }); + } else if (typeof opts.compare === 'function') { + arr.sort(opts.compare); } - /** - * Returns a throttled and proxied function for the resize handler. - * @return {function} - * @private - */ - - }, { - key: '_getResizeFunction', - value: function _getResizeFunction() { - var resizeFunction = this._handleResize.bind(this); - return this.options.throttle ? this.options.throttle(resizeFunction, this.options.throttleTime) : resizeFunction; + // Revert to the original array if necessary + if (revert) { + return original; } - /** - * Retrieve an element from an option. - * @param {string|jQuery|Element} option The option to check. - * @return {?Element} The plain element or null. - * @private - */ + if (opts.reverse) { + arr.reverse(); + } - }, { - key: '_getElementOption', - value: function _getElementOption(option) { - // If column width is a string, treat is as a selector and search for the - // sizer element within the outermost container - if (typeof option === 'string') { - return this.element.querySelector(option); + return arr; + } - // Check for an element - } else if (option && option.nodeType && option.nodeType === 1) { - return option; + var transitions = {}; + var eventName = 'transitionend'; + var count = 0; - // Check for jQuery object - } else if (option && option.jquery) { - return option[0]; - } + function uniqueId() { + count += 1; + return eventName + count; + } - return null; + function cancelTransitionEnd(id) { + if (transitions[id]) { + transitions[id].element.removeEventListener(eventName, transitions[id].listener); + transitions[id] = null; + return true; } - /** - * Ensures the shuffle container has the css styles it needs applied to it. - * @param {Object} styles Key value pairs for position and overflow. - * @private - */ + return false; + } - }, { - key: '_validateStyles', - value: function _validateStyles(styles) { - // Position cannot be static. - if (styles.position === 'static') { - this.element.style.position = 'relative'; + function onTransitionEnd(element, callback) { + var id = uniqueId(); + var listener = function listener(evt) { + if (evt.currentTarget === evt.target) { + cancelTransitionEnd(id); + callback(evt); } + }; - // Overflow has to be hidden. - if (styles.overflow !== 'hidden') { - this.element.style.overflow = 'hidden'; - } - } + element.addEventListener(eventName, listener); - /** - * Filter the elements by a category. - * @param {string|string[]|function(Element):boolean} [category] Category to - * filter by. If it's given, the last category will be used to filter the items. - * @param {Array} [collection] Optionally filter a collection. Defaults to - * all the items. - * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} - * @private - */ + transitions[id] = { element: element, listener: listener }; - }, { - key: '_filter', - value: function _filter() { - var category = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastFilter; - var collection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.items; - - var set$$1 = this._getFilteredSets(category, collection); + return id; + } - // Individually add/remove hidden/visible classes - this._toggleFilterClasses(set$$1); + function arrayMax(array) { + return Math.max.apply(Math, array); // eslint-disable-line prefer-spread + } - // Save the last filter in case elements are appended. - this.lastFilter = category; + function arrayMin(array) { + return Math.min.apply(Math, array); // eslint-disable-line prefer-spread + } - // This is saved mainly because providing a filter function (like searching) - // will overwrite the `lastFilter` property every time its called. - if (typeof category === 'string') { - this.group = category; - } + /** + * Determine the number of columns an items spans. + * @param {number} itemWidth Width of the item. + * @param {number} columnWidth Width of the column (includes gutter). + * @param {number} columns Total number of columns + * @param {number} threshold A buffer value for the size of the column to fit. + * @return {number} + */ + function getColumnSpan(itemWidth, columnWidth, columns, threshold) { + var columnSpan = itemWidth / columnWidth; - return set$$1; + // If the difference between the rounded column span number and the + // calculated column span number is really small, round the number to + // make it fit. + if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) { + // e.g. columnSpan = 4.0089945390298745 + columnSpan = Math.round(columnSpan); } - /** - * Returns an object containing the visible and hidden elements. - * @param {string|string[]|function(Element):boolean} category Category or function to filter by. - * @param {ShuffleItem[]} items A collection of items to filter. - * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} - * @private - */ + // Ensure the column span is not more than the amount of columns in the whole layout. + return Math.min(Math.ceil(columnSpan), columns); + } - }, { - key: '_getFilteredSets', - value: function _getFilteredSets(category, items) { - var _this2 = this; + /** + * Retrieves the column set to use for placement. + * @param {number} columnSpan The number of columns this current item spans. + * @param {number} columns The total columns in the grid. + * @return {Array.} An array of numbers represeting the column set. + */ + function getAvailablePositions(positions, columnSpan, columns) { + // The item spans only one column. + if (columnSpan === 1) { + return positions; + } + + // The item spans more than one column, figure out how many different + // places it could fit horizontally. + // The group count is the number of places within the positions this block + // could fit, ignoring the current positions of items. + // Imagine a 2 column brick as the second item in a 4 column grid with + // 10px height each. Find the places it would fit: + // [20, 10, 10, 0] + // | | | + // * * * + // + // Then take the places which fit and get the bigger of the two: + // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10] + // + // Next, find the first smallest number (the short column). + // [20, 10, 10] + // | + // * + // + // And that's where it should be placed! + // + // Another example where the second column's item extends past the first: + // [10, 20, 10, 0] => [20, 20, 10] => 10 + var available = []; + + // For how many possible positions for this item there are. + for (var i = 0; i <= columns - columnSpan; i++) { + // Find the bigger value for each place it could fit. + available.push(arrayMax(positions.slice(i, i + columnSpan))); + } + + return available; + } - var visible = []; - var hidden = []; + /** + * Find index of short column, the first from the left where this item will go. + * + * @param {Array.} positions The array to search for the smallest number. + * @param {number} buffer Optional buffer which is very useful when the height + * is a percentage of the width. + * @return {number} Index of the short column. + */ + function getShortColumn(positions, buffer) { + var minPosition = arrayMin(positions); + for (var i = 0, len = positions.length; i < len; i++) { + if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) { + return i; + } + } - // category === 'all', add visible class to everything - if (category === Shuffle.ALL_ITEMS) { - visible = items; + return 0; + } - // Loop through each item and use provided function to determine - // whether to hide it or not. + /** + * Determine the location of the next item, based on its size. + * @param {Object} itemSize Object with width and height. + * @param {Array.} positions Positions of the other current items. + * @param {number} gridSize The column width or row height. + * @param {number} total The total number of columns or rows. + * @param {number} threshold Buffer value for the column to fit. + * @param {number} buffer Vertical buffer for the height of items. + * @return {Point} + */ + function getItemPosition(_ref) { + var itemSize = _ref.itemSize, + positions = _ref.positions, + gridSize = _ref.gridSize, + total = _ref.total, + threshold = _ref.threshold, + buffer = _ref.buffer; + + var span = getColumnSpan(itemSize.width, gridSize, total, threshold); + var setY = getAvailablePositions(positions, span, total); + var shortColumnIndex = getShortColumn(setY, buffer); + + // Position the item + var point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]); + + // Update the columns array with the new values for each column. + // e.g. before the update the columns could be [250, 0, 0, 0] for an item + // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0]. + var setHeight = setY[shortColumnIndex] + itemSize.height; + for (var i = 0; i < span; i++) { + positions[shortColumnIndex + i] = setHeight; + } + + return point; + } + + /** + * This method attempts to center items. This method could potentially be slow + * with a large number of items because it must place items, then check every + * previous item to ensure there is no overlap. + * @param {Array.} itemRects Item data objects. + * @param {number} containerWidth Width of the containing element. + * @return {Array.} + */ + function getCenteredPositions(itemRects, containerWidth) { + var rowMap = {}; + + // Populate rows by their offset because items could jump between rows like: + // a c + // bbb + itemRects.forEach(function (itemRect) { + if (rowMap[itemRect.top]) { + // Push the point to the last row array. + rowMap[itemRect.top].push(itemRect); } else { - items.forEach(function (item) { - if (_this2._doesPassFilter(category, item.element)) { - visible.push(item); - } else { - hidden.push(item); - } - }); + // Start of a new row. + rowMap[itemRect.top] = [itemRect]; } + }); - return { - visible: visible, - hidden: hidden - }; - } + // For each row, find the end of the last item, then calculate + // the remaining space by dividing it by 2. Then add that + // offset to the x position of each point. + var rects = []; + var rows = []; + var centeredRows = []; + Object.keys(rowMap).forEach(function (key) { + var itemRects = rowMap[key]; + rows.push(itemRects); + var lastItem = itemRects[itemRects.length - 1]; + var end = lastItem.left + lastItem.width; + var offset = Math.round((containerWidth - end) / 2); + + var finalRects = itemRects; + var canMove = false; + if (offset > 0) { + var newRects = []; + canMove = itemRects.every(function (r) { + var newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id); + + // Check all current rects to make sure none overlap. + var noOverlap = !rects.some(function (r) { + return Rect.intersects(newRect, r); + }); - /** - * Test an item to see if it passes a category. - * @param {string|string[]|function():boolean} category Category or function to filter by. - * @param {Element} element An element to test. - * @return {boolean} Whether it passes the category/filter. - * @private - */ + newRects.push(newRect); + return noOverlap; + }); - }, { - key: '_doesPassFilter', - value: function _doesPassFilter(category, element) { - if (typeof category === 'function') { - return category.call(element, element, this); + // If none of the rectangles overlapped, the whole group can be centered. + if (canMove) { + finalRects = newRects; + } } - // Check each element's data-groups attribute against the given category. - var attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY); - var keys = this.options.delimiter ? attr.split(this.options.delimiter) : JSON.parse(attr); - - function testCategory(category) { - return keys.includes(category); - } + // If the items are not going to be offset, ensure that the original + // placement for this row will not overlap previous rows (row-spanning + // elements could be in the way). + if (!canMove) { + var intersectingRect = void 0; + var hasOverlap = itemRects.some(function (itemRect) { + return rects.some(function (r) { + var intersects = Rect.intersects(itemRect, r); + if (intersects) { + intersectingRect = r; + } + return intersects; + }); + }); - if (Array.isArray(category)) { - if (this.options.filterMode === Shuffle.FilterMode.ANY) { - return category.some(testCategory); + // If there is any overlap, replace the overlapping row with the original. + if (hasOverlap) { + var rowIndex = centeredRows.findIndex(function (items) { + return items.includes(intersectingRect); + }); + centeredRows.splice(rowIndex, 1, rows[rowIndex]); } - return category.every(testCategory); } - return keys.includes(category); - } - - /** - * Toggles the visible and hidden class names. - * @param {{visible, hidden}} Object with visible and hidden arrays. - * @private - */ + rects = rects.concat(finalRects); + centeredRows.push(finalRects); + }); - }, { - key: '_toggleFilterClasses', - value: function _toggleFilterClasses(_ref) { - var visible = _ref.visible, - hidden = _ref.hidden; + // Reduce array of arrays to a single array of points. + // https://stackoverflow.com/a/10865042/373422 + // Then reset sort back to how the items were passed to this method. + // Remove the wrapper object with index, map to a Point. + return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread + .sort(function (a, b) { + return a.id - b.id; + }).map(function (itemRect) { + return new Point(itemRect.left, itemRect.top); + }); + } - visible.forEach(function (item) { - item.show(); - }); + /** + * Hyphenates a javascript style string to a css one. For example: + * MozBoxSizing -> -moz-box-sizing. + * @param {string} str The string to hyphenate. + * @return {string} The hyphenated string. + */ + function hyphenate(str) { + return str.replace(/([A-Z])/g, function (str, m1) { + return "-" + m1.toLowerCase(); + }); + } - hidden.forEach(function (item) { - item.hide(); - }); - } + function arrayUnique(x) { + return Array.from(new Set(x)); + } - /** - * Set the initial css for each item - * @param {ShuffleItem[]} items Set to initialize. - * @private - */ + // Used for unique instance variables + var id$1 = 0; - }, { - key: '_initItems', - value: function _initItems(items) { - items.forEach(function (item) { - item.init(); - }); - } + var Shuffle = function (_TinyEmitter) { + inherits(Shuffle, _TinyEmitter); /** - * Remove element reference and styles. - * @param {ShuffleItem[]} items Set to dispose. - * @private + * Categorize, sort, and filter a responsive grid of items. + * + * @param {Element} element An element which is the parent container for the grid items. + * @param {Object} [options=Shuffle.options] Options object. + * @constructor */ + function Shuffle(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, Shuffle); - }, { - key: '_disposeItems', - value: function _disposeItems(items) { - items.forEach(function (item) { - item.dispose(); - }); - } + var _this = possibleConstructorReturn(this, (Shuffle.__proto__ || Object.getPrototypeOf(Shuffle)).call(this)); - /** - * Updates the visible item count. - * @private - */ + _this.options = Object.assign({}, Shuffle.options, options); - }, { - key: '_updateItemCount', - value: function _updateItemCount() { - this.visibleItems = this._getFilteredItems().length; - } + // Allow misspelling of delimiter since that's how it used to be. + // Remove in v6. + if (_this.options.delimeter) { + _this.options.delimiter = _this.options.delimeter; + } - /** - * Sets css transform transition on a group of elements. This is not executed - * at the same time as `item.init` so that transitions don't occur upon - * initialization of a new Shuffle instance. - * @param {ShuffleItem[]} items Shuffle items to set transitions on. - * @protected - */ + _this.lastSort = {}; + _this.group = Shuffle.ALL_ITEMS; + _this.lastFilter = Shuffle.ALL_ITEMS; + _this.isEnabled = true; + _this.isDestroyed = false; + _this.isInitialized = false; + _this._transitions = []; + _this.isTransitioning = false; + _this._queue = []; - }, { - key: 'setItemTransitions', - value: function setItemTransitions(items) { - var _options = this.options, - speed = _options.speed, - easing = _options.easing; + var el = _this._getElementOption(element); - var positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left']; + if (!el) { + throw new TypeError('Shuffle needs to be initialized with an element.'); + } - // Allow users to transtion other properties if they exist in the `before` - // css mapping of the shuffle item. - var cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(function (k) { - return hyphenate(k); - }); - var properties = positionProps.concat(cssProps).join(); + _this.element = el; + _this.id = 'shuffle_' + id$1; + id$1 += 1; - items.forEach(function (item) { - item.element.style.transitionDuration = speed + 'ms'; - item.element.style.transitionTimingFunction = easing; - item.element.style.transitionProperty = properties; - }); - } - }, { - key: '_getItems', - value: function _getItems() { - var _this3 = this; - - return Array.from(this.element.children).filter(function (el) { - return matchesSelector(el, _this3.options.itemSelector); - }).map(function (el) { - return new ShuffleItem(el); - }); + _this._init(); + _this.isInitialized = true; + return _this; } - /** - * Combine the current items array with a new one and sort it by DOM order. - * @param {ShuffleItem[]} items Items to track. - * @return {ShuffleItem[]} - */ + createClass(Shuffle, [{ + key: '_init', + value: function _init() { + this.items = this._getItems(); - }, { - key: '_mergeNewItems', - value: function _mergeNewItems(items) { - var children = Array.from(this.element.children); - return sorter(this.items.concat(items), { - by: function by(element) { - return children.indexOf(element); - } - }); - } - }, { - key: '_getFilteredItems', - value: function _getFilteredItems() { - return this.items.filter(function (item) { - return item.isVisible; - }); - } - }, { - key: '_getConcealedItems', - value: function _getConcealedItems() { - return this.items.filter(function (item) { - return !item.isVisible; - }); - } + this.options.sizer = this._getElementOption(this.options.sizer); - /** - * Returns the column size, based on column width and sizer options. - * @param {number} containerWidth Size of the parent container. - * @param {number} gutterSize Size of the gutters. - * @return {number} - * @private - */ + // Add class and invalidate styles + this.element.classList.add(Shuffle.Classes.BASE); - }, { - key: '_getColumnSize', - value: function _getColumnSize(containerWidth, gutterSize) { - var size = void 0; + // Set initial css for each item + this._initItems(this.items); - // If the columnWidth property is a function, then the grid is fluid - if (typeof this.options.columnWidth === 'function') { - size = this.options.columnWidth(containerWidth); + // Bind resize events + this._onResize = this._getResizeFunction(); + window.addEventListener('resize', this._onResize); - // columnWidth option isn't a function, are they using a sizing element? - } else if (this.options.sizer) { - size = Shuffle.getSize(this.options.sizer).width; + // If the page has not already emitted the `load` event, call layout on load. + // This avoids layout issues caused by images and fonts loading after the + // instance has been initialized. + if (document.readyState !== 'complete') { + var layout = this.layout.bind(this); + window.addEventListener('load', function onLoad() { + window.removeEventListener('load', onLoad); + layout(); + }); + } - // if not, how about the explicitly set option? - } else if (this.options.columnWidth) { - size = this.options.columnWidth; + // Get container css all in one request. Causes reflow + var containerCss = window.getComputedStyle(this.element, null); + var containerWidth = Shuffle.getSize(this.element).width; - // or use the size of the first item - } else if (this.items.length > 0) { - size = Shuffle.getSize(this.items[0].element, true).width; + // Add styles to the container if it doesn't have them. + this._validateStyles(containerCss); - // if there's no items, use size of container - } else { - size = containerWidth; - } + // We already got the container's width above, no need to cause another + // reflow getting it again... Calculate the number of columns there will be + this._setColumns(containerWidth); + + // Kick off! + this.filter(this.options.group, this.options.initialSort); - // Don't let them set a column width of zero. - if (size === 0) { - size = containerWidth; + // The shuffle items haven't had transitions set on them yet so the user + // doesn't see the first layout. Set them now that the first layout is done. + // First, however, a synchronous layout must be caused for the previous + // styles to be applied without transitions. + this.element.offsetWidth; // eslint-disable-line no-unused-expressions + this.setItemTransitions(this.items); + this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing; } - return size + gutterSize; - } + /** + * Returns a throttled and proxied function for the resize handler. + * @return {function} + * @private + */ + + }, { + key: '_getResizeFunction', + value: function _getResizeFunction() { + var resizeFunction = this._handleResize.bind(this); + return this.options.throttle ? this.options.throttle(resizeFunction, this.options.throttleTime) : resizeFunction; + } - /** - * Returns the gutter size, based on gutter width and sizer options. - * @param {number} containerWidth Size of the parent container. - * @return {number} - * @private - */ + /** + * Retrieve an element from an option. + * @param {string|jQuery|Element} option The option to check. + * @return {?Element} The plain element or null. + * @private + */ + + }, { + key: '_getElementOption', + value: function _getElementOption(option) { + // If column width is a string, treat is as a selector and search for the + // sizer element within the outermost container + if (typeof option === 'string') { + return this.element.querySelector(option); + + // Check for an element + } else if (option && option.nodeType && option.nodeType === 1) { + return option; + + // Check for jQuery object + } else if (option && option.jquery) { + return option[0]; + } - }, { - key: '_getGutterSize', - value: function _getGutterSize(containerWidth) { - var size = void 0; - if (typeof this.options.gutterWidth === 'function') { - size = this.options.gutterWidth(containerWidth); - } else if (this.options.sizer) { - size = getNumberStyle(this.options.sizer, 'marginLeft'); - } else { - size = this.options.gutterWidth; + return null; } - return size; - } + /** + * Ensures the shuffle container has the css styles it needs applied to it. + * @param {Object} styles Key value pairs for position and overflow. + * @private + */ + + }, { + key: '_validateStyles', + value: function _validateStyles(styles) { + // Position cannot be static. + if (styles.position === 'static') { + this.element.style.position = 'relative'; + } - /** - * Calculate the number of columns to be used. Gets css if using sizer element. - * @param {number} [containerWidth] Optionally specify a container width if - * it's already available. - */ + // Overflow has to be hidden. + if (styles.overflow !== 'hidden') { + this.element.style.overflow = 'hidden'; + } + } + + /** + * Filter the elements by a category. + * @param {string|string[]|function(Element):boolean} [category] Category to + * filter by. If it's given, the last category will be used to filter the items. + * @param {Array} [collection] Optionally filter a collection. Defaults to + * all the items. + * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} + * @private + */ + + }, { + key: '_filter', + value: function _filter() { + var category = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastFilter; + var collection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.items; + + var set$$1 = this._getFilteredSets(category, collection); + + // Individually add/remove hidden/visible classes + this._toggleFilterClasses(set$$1); + + // Save the last filter in case elements are appended. + this.lastFilter = category; + + // This is saved mainly because providing a filter function (like searching) + // will overwrite the `lastFilter` property every time its called. + if (typeof category === 'string') { + this.group = category; + } - }, { - key: '_setColumns', - value: function _setColumns() { - var containerWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Shuffle.getSize(this.element).width; + return set$$1; + } - var gutter = this._getGutterSize(containerWidth); - var columnWidth = this._getColumnSize(containerWidth, gutter); - var calculatedColumns = (containerWidth + gutter) / columnWidth; + /** + * Returns an object containing the visible and hidden elements. + * @param {string|string[]|function(Element):boolean} category Category or function to filter by. + * @param {ShuffleItem[]} items A collection of items to filter. + * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} + * @private + */ + + }, { + key: '_getFilteredSets', + value: function _getFilteredSets(category, items) { + var _this2 = this; + + var visible = []; + var hidden = []; + + // category === 'all', add visible class to everything + if (category === Shuffle.ALL_ITEMS) { + visible = items; + + // Loop through each item and use provided function to determine + // whether to hide it or not. + } else { + items.forEach(function (item) { + if (_this2._doesPassFilter(category, item.element)) { + visible.push(item); + } else { + hidden.push(item); + } + }); + } - // Widths given from getStyles are not precise enough... - if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) < this.options.columnThreshold) { - // e.g. calculatedColumns = 11.998876 - calculatedColumns = Math.round(calculatedColumns); + return { + visible: visible, + hidden: hidden + }; } - this.cols = Math.max(Math.floor(calculatedColumns), 1); - this.containerWidth = containerWidth; - this.colWidth = columnWidth; - } + /** + * Test an item to see if it passes a category. + * @param {string|string[]|function():boolean} category Category or function to filter by. + * @param {Element} element An element to test. + * @return {boolean} Whether it passes the category/filter. + * @private + */ + + }, { + key: '_doesPassFilter', + value: function _doesPassFilter(category, element) { + if (typeof category === 'function') { + return category.call(element, element, this); + } - /** - * Adjust the height of the grid - */ + // Check each element's data-groups attribute against the given category. + var attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY); + var keys = this.options.delimiter ? attr.split(this.options.delimiter) : JSON.parse(attr); - }, { - key: '_setContainerSize', - value: function _setContainerSize() { - this.element.style.height = this._getContainerSize() + 'px'; - } + function testCategory(category) { + return keys.includes(category); + } + + if (Array.isArray(category)) { + if (this.options.filterMode === Shuffle.FilterMode.ANY) { + return category.some(testCategory); + } + return category.every(testCategory); + } - /** - * Based on the column heights, it returns the biggest one. - * @return {number} - * @private - */ + return keys.includes(category); + } - }, { - key: '_getContainerSize', - value: function _getContainerSize() { - return arrayMax(this.positions); - } + /** + * Toggles the visible and hidden class names. + * @param {{visible, hidden}} Object with visible and hidden arrays. + * @private + */ - /** - * Get the clamped stagger amount. - * @param {number} index Index of the item to be staggered. - * @return {number} - */ + }, { + key: '_toggleFilterClasses', + value: function _toggleFilterClasses(_ref) { + var visible = _ref.visible, + hidden = _ref.hidden; - }, { - key: '_getStaggerAmount', - value: function _getStaggerAmount(index) { - return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax); - } + visible.forEach(function (item) { + item.show(); + }); - /** - * Emit an event from this instance. - * @param {string} name Event name. - * @param {Object} [data={}] Optional object data. - */ + hidden.forEach(function (item) { + item.hide(); + }); + } - }, { - key: '_dispatch', - value: function _dispatch(name) { - var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + /** + * Set the initial css for each item + * @param {ShuffleItem[]} items Set to initialize. + * @private + */ - if (this.isDestroyed) { - return; + }, { + key: '_initItems', + value: function _initItems(items) { + items.forEach(function (item) { + item.init(); + }); } - data.shuffle = this; - this.emit(name, data); - } + /** + * Remove element reference and styles. + * @param {ShuffleItem[]} items Set to dispose. + * @private + */ - /** - * Zeros out the y columns array, which is used to determine item placement. - * @private - */ + }, { + key: '_disposeItems', + value: function _disposeItems(items) { + items.forEach(function (item) { + item.dispose(); + }); + } + + /** + * Updates the visible item count. + * @private + */ - }, { - key: '_resetCols', - value: function _resetCols() { - var i = this.cols; - this.positions = []; - while (i) { - i -= 1; - this.positions.push(0); + }, { + key: '_updateItemCount', + value: function _updateItemCount() { + this.visibleItems = this._getFilteredItems().length; } - } - /** - * Loops through each item that should be shown and calculates the x, y position. - * @param {ShuffleItem[]} items Array of items that will be shown/layed - * out in order in their array. - */ + /** + * Sets css transform transition on a group of elements. This is not executed + * at the same time as `item.init` so that transitions don't occur upon + * initialization of a new Shuffle instance. + * @param {ShuffleItem[]} items Shuffle items to set transitions on. + * @protected + */ + + }, { + key: 'setItemTransitions', + value: function setItemTransitions(items) { + var _options = this.options, + speed = _options.speed, + easing = _options.easing; + + var positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left']; + + // Allow users to transtion other properties if they exist in the `before` + // css mapping of the shuffle item. + var cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(function (k) { + return hyphenate(k); + }); + var properties = positionProps.concat(cssProps).join(); - }, { - key: '_layout', - value: function _layout(items) { - var _this4 = this; + items.forEach(function (item) { + item.element.style.transitionDuration = speed + 'ms'; + item.element.style.transitionTimingFunction = easing; + item.element.style.transitionProperty = properties; + }); + } + }, { + key: '_getItems', + value: function _getItems() { + var _this3 = this; + + return Array.from(this.element.children).filter(function (el) { + return matchesSelector(el, _this3.options.itemSelector); + }).map(function (el) { + return new ShuffleItem(el); + }); + } - var itemPositions = this._getNextPositions(items); + /** + * Combine the current items array with a new one and sort it by DOM order. + * @param {ShuffleItem[]} items Items to track. + * @return {ShuffleItem[]} + */ + + }, { + key: '_mergeNewItems', + value: function _mergeNewItems(items) { + var children = Array.from(this.element.children); + return sorter(this.items.concat(items), { + by: function by(element) { + return children.indexOf(element); + } + }); + } + }, { + key: '_getFilteredItems', + value: function _getFilteredItems() { + return this.items.filter(function (item) { + return item.isVisible; + }); + } + }, { + key: '_getConcealedItems', + value: function _getConcealedItems() { + return this.items.filter(function (item) { + return !item.isVisible; + }); + } - var count = 0; - items.forEach(function (item, i) { - function callback() { - item.applyCss(ShuffleItem.Css.VISIBLE.after); + /** + * Returns the column size, based on column width and sizer options. + * @param {number} containerWidth Size of the parent container. + * @param {number} gutterSize Size of the gutters. + * @return {number} + * @private + */ + + }, { + key: '_getColumnSize', + value: function _getColumnSize(containerWidth, gutterSize) { + var size = void 0; + + // If the columnWidth property is a function, then the grid is fluid + if (typeof this.options.columnWidth === 'function') { + size = this.options.columnWidth(containerWidth); + + // columnWidth option isn't a function, are they using a sizing element? + } else if (this.options.sizer) { + size = Shuffle.getSize(this.options.sizer).width; + + // if not, how about the explicitly set option? + } else if (this.options.columnWidth) { + size = this.options.columnWidth; + + // or use the size of the first item + } else if (this.items.length > 0) { + size = Shuffle.getSize(this.items[0].element, true).width; + + // if there's no items, use size of container + } else { + size = containerWidth; } - // If the item will not change its position, do not add it to the render - // queue. Transitions don't fire when setting a property to the same value. - if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) { - item.applyCss(ShuffleItem.Css.VISIBLE.before); - callback(); - return; + // Don't let them set a column width of zero. + if (size === 0) { + size = containerWidth; } - item.point = itemPositions[i]; - item.scale = ShuffleItem.Scale.VISIBLE; - item.isHidden = false; + return size + gutterSize; + } - // Clone the object so that the `before` object isn't modified when the - // transition delay is added. - var styles = _this4.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before); - styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms'; + /** + * Returns the gutter size, based on gutter width and sizer options. + * @param {number} containerWidth Size of the parent container. + * @return {number} + * @private + */ + + }, { + key: '_getGutterSize', + value: function _getGutterSize(containerWidth) { + var size = void 0; + if (typeof this.options.gutterWidth === 'function') { + size = this.options.gutterWidth(containerWidth); + } else if (this.options.sizer) { + size = getNumberStyle(this.options.sizer, 'marginLeft'); + } else { + size = this.options.gutterWidth; + } - _this4._queue.push({ - item: item, - styles: styles, - callback: callback - }); + return size; + } - count += 1; - }); - } + /** + * Calculate the number of columns to be used. Gets css if using sizer element. + * @param {number} [containerWidth] Optionally specify a container width if + * it's already available. + */ + + }, { + key: '_setColumns', + value: function _setColumns() { + var containerWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Shuffle.getSize(this.element).width; + + var gutter = this._getGutterSize(containerWidth); + var columnWidth = this._getColumnSize(containerWidth, gutter); + var calculatedColumns = (containerWidth + gutter) / columnWidth; + + // Widths given from getStyles are not precise enough... + if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) < this.options.columnThreshold) { + // e.g. calculatedColumns = 11.998876 + calculatedColumns = Math.round(calculatedColumns); + } - /** - * Return an array of Point instances representing the future positions of - * each item. - * @param {ShuffleItem[]} items Array of sorted shuffle items. - * @return {Point[]} - * @private - */ + this.cols = Math.max(Math.floor(calculatedColumns), 1); + this.containerWidth = containerWidth; + this.colWidth = columnWidth; + } - }, { - key: '_getNextPositions', - value: function _getNextPositions(items) { - var _this5 = this; - - // If position data is going to be changed, add the item's size to the - // transformer to allow for calculations. - if (this.options.isCentered) { - var itemsData = items.map(function (item, i) { - var itemSize = Shuffle.getSize(item.element, true); - var point = _this5._getItemPosition(itemSize); - return new Rect(point.x, point.y, itemSize.width, itemSize.height, i); - }); + /** + * Adjust the height of the grid + */ - return this.getTransformedPositions(itemsData, this.containerWidth); + }, { + key: '_setContainerSize', + value: function _setContainerSize() { + this.element.style.height = this._getContainerSize() + 'px'; } - // If no transforms are going to happen, simply return an array of the - // future points of each item. - return items.map(function (item) { - return _this5._getItemPosition(Shuffle.getSize(item.element, true)); - }); - } + /** + * Based on the column heights, it returns the biggest one. + * @return {number} + * @private + */ - /** - * Determine the location of the next item, based on its size. - * @param {{width: number, height: number}} itemSize Object with width and height. - * @return {Point} - * @private - */ + }, { + key: '_getContainerSize', + value: function _getContainerSize() { + return arrayMax(this.positions); + } - }, { - key: '_getItemPosition', - value: function _getItemPosition(itemSize) { - return getItemPosition({ - itemSize: itemSize, - positions: this.positions, - gridSize: this.colWidth, - total: this.cols, - threshold: this.options.columnThreshold, - buffer: this.options.buffer - }); - } + /** + * Get the clamped stagger amount. + * @param {number} index Index of the item to be staggered. + * @return {number} + */ - /** - * Mutate positions before they're applied. - * @param {Rect[]} itemRects Item data objects. - * @param {number} containerWidth Width of the containing element. - * @return {Point[]} - * @protected - */ + }, { + key: '_getStaggerAmount', + value: function _getStaggerAmount(index) { + return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax); + } - }, { - key: 'getTransformedPositions', - value: function getTransformedPositions(itemRects, containerWidth) { - return getCenteredPositions(itemRects, containerWidth); - } + /** + * Emit an event from this instance. + * @param {string} name Event name. + * @param {Object} [data={}] Optional object data. + */ - /** - * Hides the elements that don't match our filter. - * @param {ShuffleItem[]} collection Collection to shrink. - * @private - */ + }, { + key: '_dispatch', + value: function _dispatch(name) { + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - }, { - key: '_shrink', - value: function _shrink() { - var _this6 = this; + if (this.isDestroyed) { + return; + } - var collection = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._getConcealedItems(); + data.shuffle = this; + this.emit(name, data); + } - var count = 0; - collection.forEach(function (item) { - function callback() { - item.applyCss(ShuffleItem.Css.HIDDEN.after); + /** + * Zeros out the y columns array, which is used to determine item placement. + * @private + */ + + }, { + key: '_resetCols', + value: function _resetCols() { + var i = this.cols; + this.positions = []; + while (i) { + i -= 1; + this.positions.push(0); } + } - // Continuing would add a transitionend event listener to the element, but - // that listener would not execute because the transform and opacity would - // stay the same. - // The callback is executed here because it is not guaranteed to be called - // after the transitionend event because the transitionend could be - // canceled if another animation starts. - if (item.isHidden) { - item.applyCss(ShuffleItem.Css.HIDDEN.before); - callback(); - return; - } + /** + * Loops through each item that should be shown and calculates the x, y position. + * @param {ShuffleItem[]} items Array of items that will be shown/layed + * out in order in their array. + */ - item.scale = ShuffleItem.Scale.HIDDEN; - item.isHidden = true; + }, { + key: '_layout', + value: function _layout(items) { + var _this4 = this; - var styles = _this6.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before); - styles.transitionDelay = _this6._getStaggerAmount(count) + 'ms'; + var itemPositions = this._getNextPositions(items); - _this6._queue.push({ - item: item, - styles: styles, - callback: callback - }); + var count = 0; + items.forEach(function (item, i) { + function callback() { + item.applyCss(ShuffleItem.Css.VISIBLE.after); + } - count += 1; - }); - } + // If the item will not change its position, do not add it to the render + // queue. Transitions don't fire when setting a property to the same value. + if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) { + item.applyCss(ShuffleItem.Css.VISIBLE.before); + callback(); + return; + } - /** - * Resize handler. - * @private - */ + item.point = itemPositions[i]; + item.scale = ShuffleItem.Scale.VISIBLE; + item.isHidden = false; + + // Clone the object so that the `before` object isn't modified when the + // transition delay is added. + var styles = _this4.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before); + styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms'; + + _this4._queue.push({ + item: item, + styles: styles, + callback: callback + }); - }, { - key: '_handleResize', - value: function _handleResize() { - // If shuffle is disabled, destroyed, don't do anything - if (!this.isEnabled || this.isDestroyed) { - return; + count += 1; + }); } - this.update(); - } + /** + * Return an array of Point instances representing the future positions of + * each item. + * @param {ShuffleItem[]} items Array of sorted shuffle items. + * @return {Point[]} + * @private + */ + + }, { + key: '_getNextPositions', + value: function _getNextPositions(items) { + var _this5 = this; + + // If position data is going to be changed, add the item's size to the + // transformer to allow for calculations. + if (this.options.isCentered) { + var itemsData = items.map(function (item, i) { + var itemSize = Shuffle.getSize(item.element, true); + var point = _this5._getItemPosition(itemSize); + return new Rect(point.x, point.y, itemSize.width, itemSize.height, i); + }); - /** - * Returns styles which will be applied to the an item for a transition. - * @param {ShuffleItem} item Item to get styles for. Should have updated - * scale and point properties. - * @param {Object} styleObject Extra styles that will be used in the transition. - * @return {!Object} Transforms for transitions, left/top for animate. - * @protected - */ + return this.getTransformedPositions(itemsData, this.containerWidth); + } - }, { - key: 'getStylesForTransition', - value: function getStylesForTransition(item, styleObject) { - // Clone the object to avoid mutating the original. - var styles = Object.assign({}, styleObject); + // If no transforms are going to happen, simply return an array of the + // future points of each item. + return items.map(function (item) { + return _this5._getItemPosition(Shuffle.getSize(item.element, true)); + }); + } - if (this.options.useTransforms) { - var x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x; - var y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y; - styles.transform = 'translate(' + x + 'px, ' + y + 'px) scale(' + item.scale + ')'; - } else { - styles.left = item.point.x + 'px'; - styles.top = item.point.y + 'px'; + /** + * Determine the location of the next item, based on its size. + * @param {{width: number, height: number}} itemSize Object with width and height. + * @return {Point} + * @private + */ + + }, { + key: '_getItemPosition', + value: function _getItemPosition(itemSize) { + return getItemPosition({ + itemSize: itemSize, + positions: this.positions, + gridSize: this.colWidth, + total: this.cols, + threshold: this.options.columnThreshold, + buffer: this.options.buffer + }); } - return styles; - } + /** + * Mutate positions before they're applied. + * @param {Rect[]} itemRects Item data objects. + * @param {number} containerWidth Width of the containing element. + * @return {Point[]} + * @protected + */ + + }, { + key: 'getTransformedPositions', + value: function getTransformedPositions(itemRects, containerWidth) { + return getCenteredPositions(itemRects, containerWidth); + } - /** - * Listen for the transition end on an element and execute the itemCallback - * when it finishes. - * @param {Element} element Element to listen on. - * @param {function} itemCallback Callback for the item. - * @param {function} done Callback to notify `parallel` that this one is done. - */ + /** + * Hides the elements that don't match our filter. + * @param {ShuffleItem[]} collection Collection to shrink. + * @private + */ - }, { - key: '_whenTransitionDone', - value: function _whenTransitionDone(element, itemCallback, done) { - var id = onTransitionEnd(element, function (evt) { - itemCallback(); - done(null, evt); - }); + }, { + key: '_shrink', + value: function _shrink() { + var _this6 = this; - this._transitions.push(id); - } + var collection = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._getConcealedItems(); - /** - * Return a function which will set CSS styles and call the `done` function - * when (if) the transition finishes. - * @param {Object} opts Transition object. - * @return {function} A function to be called with a `done` function. - */ + var count = 0; + collection.forEach(function (item) { + function callback() { + item.applyCss(ShuffleItem.Css.HIDDEN.after); + } - }, { - key: '_getTransitionFunction', - value: function _getTransitionFunction(opts) { - var _this7 = this; + // Continuing would add a transitionend event listener to the element, but + // that listener would not execute because the transform and opacity would + // stay the same. + // The callback is executed here because it is not guaranteed to be called + // after the transitionend event because the transitionend could be + // canceled if another animation starts. + if (item.isHidden) { + item.applyCss(ShuffleItem.Css.HIDDEN.before); + callback(); + return; + } - return function (done) { - opts.item.applyCss(opts.styles); - _this7._whenTransitionDone(opts.item.element, opts.callback, done); - }; - } + item.scale = ShuffleItem.Scale.HIDDEN; + item.isHidden = true; - /** - * Execute the styles gathered in the style queue. This applies styles to elements, - * triggering transitions. - * @private - */ + var styles = _this6.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before); + styles.transitionDelay = _this6._getStaggerAmount(count) + 'ms'; - }, { - key: '_processQueue', - value: function _processQueue() { - if (this.isTransitioning) { - this._cancelMovement(); + _this6._queue.push({ + item: item, + styles: styles, + callback: callback + }); + + count += 1; + }); } - var hasSpeed = this.options.speed > 0; - var hasQueue = this._queue.length > 0; + /** + * Resize handler. + * @private + */ - if (hasQueue && hasSpeed && this.isInitialized) { - this._startTransitions(this._queue); - } else if (hasQueue) { - this._styleImmediately(this._queue); - this._dispatch(Shuffle.EventType.LAYOUT); + }, { + key: '_handleResize', + value: function _handleResize() { + // If shuffle is disabled, destroyed, don't do anything + if (!this.isEnabled || this.isDestroyed) { + return; + } - // A call to layout happened, but none of the newly visible items will - // change position or the transition duration is zero, which will not trigger - // the transitionend event. - } else { - this._dispatch(Shuffle.EventType.LAYOUT); + this.update(); } - // Remove everything in the style queue - this._queue.length = 0; - } + /** + * Returns styles which will be applied to the an item for a transition. + * @param {ShuffleItem} item Item to get styles for. Should have updated + * scale and point properties. + * @param {Object} styleObject Extra styles that will be used in the transition. + * @return {!Object} Transforms for transitions, left/top for animate. + * @protected + */ + + }, { + key: 'getStylesForTransition', + value: function getStylesForTransition(item, styleObject) { + // Clone the object to avoid mutating the original. + var styles = Object.assign({}, styleObject); + + if (this.options.useTransforms) { + var x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x; + var y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y; + styles.transform = 'translate(' + x + 'px, ' + y + 'px) scale(' + item.scale + ')'; + } else { + styles.left = item.point.x + 'px'; + styles.top = item.point.y + 'px'; + } - /** - * Wait for each transition to finish, the emit the layout event. - * @param {Object[]} transitions Array of transition objects. - */ + return styles; + } - }, { - key: '_startTransitions', - value: function _startTransitions(transitions) { - var _this8 = this; + /** + * Listen for the transition end on an element and execute the itemCallback + * when it finishes. + * @param {Element} element Element to listen on. + * @param {function} itemCallback Callback for the item. + * @param {function} done Callback to notify `parallel` that this one is done. + */ + + }, { + key: '_whenTransitionDone', + value: function _whenTransitionDone(element, itemCallback, done) { + var id = onTransitionEnd(element, function (evt) { + itemCallback(); + done(null, evt); + }); - // Set flag that shuffle is currently in motion. - this.isTransitioning = true; + this._transitions.push(id); + } - // Create an array of functions to be called. - var callbacks = transitions.map(function (obj) { - return _this8._getTransitionFunction(obj); - }); + /** + * Return a function which will set CSS styles and call the `done` function + * when (if) the transition finishes. + * @param {Object} opts Transition object. + * @return {function} A function to be called with a `done` function. + */ + + }, { + key: '_getTransitionFunction', + value: function _getTransitionFunction(opts) { + var _this7 = this; + + return function (done) { + opts.item.applyCss(opts.styles); + _this7._whenTransitionDone(opts.item.element, opts.callback, done); + }; + } - arrayParallel(callbacks, this._movementFinished.bind(this)); - } - }, { - key: '_cancelMovement', - value: function _cancelMovement() { - // Remove the transition end event for each listener. - this._transitions.forEach(cancelTransitionEnd); + /** + * Execute the styles gathered in the style queue. This applies styles to elements, + * triggering transitions. + * @private + */ + + }, { + key: '_processQueue', + value: function _processQueue() { + if (this.isTransitioning) { + this._cancelMovement(); + } - // Reset the array. - this._transitions.length = 0; + var hasSpeed = this.options.speed > 0; + var hasQueue = this._queue.length > 0; - // Show it's no longer active. - this.isTransitioning = false; - } + if (hasQueue && hasSpeed && this.isInitialized) { + this._startTransitions(this._queue); + } else if (hasQueue) { + this._styleImmediately(this._queue); + this._dispatch(Shuffle.EventType.LAYOUT); - /** - * Apply styles without a transition. - * @param {Object[]} objects Array of transition objects. - * @private - */ + // A call to layout happened, but none of the newly visible items will + // change position or the transition duration is zero, which will not trigger + // the transitionend event. + } else { + this._dispatch(Shuffle.EventType.LAYOUT); + } - }, { - key: '_styleImmediately', - value: function _styleImmediately(objects) { - if (objects.length) { - var elements = objects.map(function (obj) { - return obj.item.element; - }); + // Remove everything in the style queue + this._queue.length = 0; + } - Shuffle._skipTransitions(elements, function () { - objects.forEach(function (obj) { - obj.item.applyCss(obj.styles); - obj.callback(); - }); + /** + * Wait for each transition to finish, the emit the layout event. + * @param {Object[]} transitions Array of transition objects. + */ + + }, { + key: '_startTransitions', + value: function _startTransitions(transitions) { + var _this8 = this; + + // Set flag that shuffle is currently in motion. + this.isTransitioning = true; + + // Create an array of functions to be called. + var callbacks = transitions.map(function (obj) { + return _this8._getTransitionFunction(obj); }); + + arrayParallel(callbacks, this._movementFinished.bind(this)); } - } - }, { - key: '_movementFinished', - value: function _movementFinished() { - this._transitions.length = 0; - this.isTransitioning = false; - this._dispatch(Shuffle.EventType.LAYOUT); - } + }, { + key: '_cancelMovement', + value: function _cancelMovement() { + // Remove the transition end event for each listener. + this._transitions.forEach(cancelTransitionEnd); - /** - * The magic. This is what makes the plugin 'shuffle' - * @param {string|string[]|function(Element):boolean} [category] Category to filter by. - * Can be a function, string, or array of strings. - * @param {Object} [sortObj] A sort object which can sort the visible set - */ + // Reset the array. + this._transitions.length = 0; - }, { - key: 'filter', - value: function filter(category, sortObj) { - if (!this.isEnabled) { - return; + // Show it's no longer active. + this.isTransitioning = false; } - if (!category || category && category.length === 0) { - category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign - } + /** + * Apply styles without a transition. + * @param {Object[]} objects Array of transition objects. + * @private + */ + + }, { + key: '_styleImmediately', + value: function _styleImmediately(objects) { + if (objects.length) { + var elements = objects.map(function (obj) { + return obj.item.element; + }); - this._filter(category); + Shuffle._skipTransitions(elements, function () { + objects.forEach(function (obj) { + obj.item.applyCss(obj.styles); + obj.callback(); + }); + }); + } + } + }, { + key: '_movementFinished', + value: function _movementFinished() { + this._transitions.length = 0; + this.isTransitioning = false; + this._dispatch(Shuffle.EventType.LAYOUT); + } - // Shrink each hidden item - this._shrink(); + /** + * The magic. This is what makes the plugin 'shuffle' + * @param {string|string[]|function(Element):boolean} [category] Category to filter by. + * Can be a function, string, or array of strings. + * @param {Object} [sortObj] A sort object which can sort the visible set + */ + + }, { + key: 'filter', + value: function filter(category, sortObj) { + if (!this.isEnabled) { + return; + } - // How many visible elements? - this._updateItemCount(); + if (!category || category && category.length === 0) { + category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign + } - // Update transforms on visible elements so they will animate to their new positions. - this.sort(sortObj); - } + this._filter(category); - /** - * Gets the visible elements, sorts them, and passes them to layout. - * @param {Object} [sortOptions] The options object to pass to `sorter`. - */ + // Shrink each hidden item + this._shrink(); - }, { - key: 'sort', - value: function sort() { - var sortOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort; + // How many visible elements? + this._updateItemCount(); - if (!this.isEnabled) { - return; + // Update transforms on visible elements so they will animate to their new positions. + this.sort(sortObj); } - this._resetCols(); - - var items = sorter(this._getFilteredItems(), sortOptions); + /** + * Gets the visible elements, sorts them, and passes them to layout. + * @param {Object} [sortOptions] The options object to pass to `sorter`. + */ - this._layout(items); + }, { + key: 'sort', + value: function sort() { + var sortOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort; - // `_layout` always happens after `_shrink`, so it's safe to process the style - // queue here with styles from the shrink method. - this._processQueue(); + if (!this.isEnabled) { + return; + } - // Adjust the height of the container. - this._setContainerSize(); + this._resetCols(); - this.lastSort = sortOptions; - } + var items = sorter(this._getFilteredItems(), sortOptions); - /** - * Reposition everything. - * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated. - */ + this._layout(items); - }, { - key: 'update', - value: function update() { - var isOnlyLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + // `_layout` always happens after `_shrink`, so it's safe to process the style + // queue here with styles from the shrink method. + this._processQueue(); - if (this.isEnabled) { - if (!isOnlyLayout) { - // Get updated colCount - this._setColumns(); - } + // Adjust the height of the container. + this._setContainerSize(); - // Layout items - this.sort(); + this.lastSort = sortOptions; } - } - /** - * Use this instead of `update()` if you don't need the columns and gutters updated - * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations - * could be off. - */ + /** + * Reposition everything. + * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated. + */ - }, { - key: 'layout', - value: function layout() { - this.update(true); - } + }, { + key: 'update', + value: function update() { + var isOnlyLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - /** - * New items have been appended to shuffle. Mix them in with the current - * filter or sort status. - * @param {Element[]} newItems Collection of new items. - */ + if (this.isEnabled) { + if (!isOnlyLayout) { + // Get updated colCount + this._setColumns(); + } - }, { - key: 'add', - value: function add(newItems) { - var _this9 = this; + // Layout items + this.sort(); + } + } - var items = arrayUnique(newItems).map(function (el) { - return new ShuffleItem(el); - }); + /** + * Use this instead of `update()` if you don't need the columns and gutters updated + * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations + * could be off. + */ - // Add classes and set initial positions. - this._initItems(items); - - // Determine which items will go with the current filter. - this._resetCols(); - - var allItems = this._mergeNewItems(items); - var sortedItems = sorter(allItems, this.lastSort); - var allSortedItemsSet = this._filter(this.lastFilter, sortedItems); - - var isNewItem = function isNewItem(item) { - return items.includes(item); - }; - var applyHiddenState = function applyHiddenState(item) { - item.scale = ShuffleItem.Scale.HIDDEN; - item.isHidden = true; - item.applyCss(ShuffleItem.Css.HIDDEN.before); - item.applyCss(ShuffleItem.Css.HIDDEN.after); - }; - - // Layout all items again so that new items get positions. - // Synchonously apply positions. - var itemPositions = this._getNextPositions(allSortedItemsSet.visible); - allSortedItemsSet.visible.forEach(function (item, i) { - if (isNewItem(item)) { - item.point = itemPositions[i]; - applyHiddenState(item); - item.applyCss(_this9.getStylesForTransition(item, {})); - } - }); + }, { + key: 'layout', + value: function layout() { + this.update(true); + } - allSortedItemsSet.hidden.forEach(function (item) { - if (isNewItem(item)) { - applyHiddenState(item); - } - }); + /** + * New items have been appended to shuffle. Mix them in with the current + * filter or sort status. + * @param {Element[]} newItems Collection of new items. + */ - // Cause layout so that the styles above are applied. - this.element.offsetWidth; // eslint-disable-line no-unused-expressions + }, { + key: 'add', + value: function add(newItems) { + var _this9 = this; - // Add transition to each item. - this.setItemTransitions(items); + var items = arrayUnique(newItems).map(function (el) { + return new ShuffleItem(el); + }); - // Update the list of items. - this.items = this._mergeNewItems(items); + // Add classes and set initial positions. + this._initItems(items); - // Update layout/visibility of new and old items. - this.filter(this.lastFilter); - } + // Determine which items will go with the current filter. + this._resetCols(); - /** - * Disables shuffle from updating dimensions and layout on resize - */ + var allItems = this._mergeNewItems(items); + var sortedItems = sorter(allItems, this.lastSort); + var allSortedItemsSet = this._filter(this.lastFilter, sortedItems); - }, { - key: 'disable', - value: function disable() { - this.isEnabled = false; - } + var isNewItem = function isNewItem(item) { + return items.includes(item); + }; + var applyHiddenState = function applyHiddenState(item) { + item.scale = ShuffleItem.Scale.HIDDEN; + item.isHidden = true; + item.applyCss(ShuffleItem.Css.HIDDEN.before); + item.applyCss(ShuffleItem.Css.HIDDEN.after); + }; - /** - * Enables shuffle again - * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters - */ + // Layout all items again so that new items get positions. + // Synchonously apply positions. + var itemPositions = this._getNextPositions(allSortedItemsSet.visible); + allSortedItemsSet.visible.forEach(function (item, i) { + if (isNewItem(item)) { + item.point = itemPositions[i]; + applyHiddenState(item); + item.applyCss(_this9.getStylesForTransition(item, {})); + } + }); - }, { - key: 'enable', - value: function enable() { - var isUpdateLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + allSortedItemsSet.hidden.forEach(function (item) { + if (isNewItem(item)) { + applyHiddenState(item); + } + }); - this.isEnabled = true; - if (isUpdateLayout) { - this.update(); - } - } + // Cause layout so that the styles above are applied. + this.element.offsetWidth; // eslint-disable-line no-unused-expressions - /** - * Remove 1 or more shuffle items. - * @param {Element[]} elements An array containing one or more - * elements in shuffle - * @return {Shuffle} The shuffle instance. - */ + // Add transition to each item. + this.setItemTransitions(items); - }, { - key: 'remove', - value: function remove(elements) { - var _this10 = this; + // Update the list of items. + this.items = this._mergeNewItems(items); - if (!elements.length) { - return; + // Update layout/visibility of new and old items. + this.filter(this.lastFilter); } - var collection = arrayUnique(elements); + /** + * Disables shuffle from updating dimensions and layout on resize + */ - var oldItems = collection.map(function (element) { - return _this10.getItemByElement(element); - }).filter(function (item) { - return !!item; - }); + }, { + key: 'disable', + value: function disable() { + this.isEnabled = false; + } - var handleLayout = function handleLayout() { - _this10._disposeItems(oldItems); + /** + * Enables shuffle again + * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters + */ - // Remove the collection in the callback - collection.forEach(function (element) { - element.parentNode.removeChild(element); - }); + }, { + key: 'enable', + value: function enable() { + var isUpdateLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; - _this10._dispatch(Shuffle.EventType.REMOVED, { collection: collection }); - }; + this.isEnabled = true; + if (isUpdateLayout) { + this.update(); + } + } - // Hide collection first. - this._toggleFilterClasses({ - visible: [], - hidden: oldItems - }); + /** + * Remove 1 or more shuffle items. + * @param {Element[]} elements An array containing one or more + * elements in shuffle + * @return {Shuffle} The shuffle instance. + */ - this._shrink(oldItems); + }, { + key: 'remove', + value: function remove(elements) { + var _this10 = this; - this.sort(); + if (!elements.length) { + return; + } - // Update the list of items here because `remove` could be called again - // with an item that is in the process of being removed. - this.items = this.items.filter(function (item) { - return !oldItems.includes(item); - }); - this._updateItemCount(); + var collection = arrayUnique(elements); - this.once(Shuffle.EventType.LAYOUT, handleLayout); - } + var oldItems = collection.map(function (element) { + return _this10.getItemByElement(element); + }).filter(function (item) { + return !!item; + }); - /** - * Retrieve a shuffle item by its element. - * @param {Element} element Element to look for. - * @return {?ShuffleItem} A shuffle item or undefined if it's not found. - */ + var handleLayout = function handleLayout() { + _this10._disposeItems(oldItems); - }, { - key: 'getItemByElement', - value: function getItemByElement(element) { - return this.items.find(function (item) { - return item.element === element; - }); - } + // Remove the collection in the callback + collection.forEach(function (element) { + element.parentNode.removeChild(element); + }); - /** - * Dump the elements currently stored and reinitialize all child elements which - * match the `itemSelector`. - */ + _this10._dispatch(Shuffle.EventType.REMOVED, { collection: collection }); + }; - }, { - key: 'resetItems', - value: function resetItems() { - var _this11 = this; + // Hide collection first. + this._toggleFilterClasses({ + visible: [], + hidden: oldItems + }); - // Remove refs to current items. - this._disposeItems(this.items); - this.isInitialized = false; + this._shrink(oldItems); - // Find new items in the DOM. - this.items = this._getItems(); + this.sort(); - // Set initial styles on the new items. - this._initItems(this.items); + // Update the list of items here because `remove` could be called again + // with an item that is in the process of being removed. + this.items = this.items.filter(function (item) { + return !oldItems.includes(item); + }); + this._updateItemCount(); - this.once(Shuffle.EventType.LAYOUT, function () { - // Add transition to each item. - _this11.setItemTransitions(_this11.items); - _this11.isInitialized = true; - }); + this.once(Shuffle.EventType.LAYOUT, handleLayout); + } - // Lay out all items. - this.filter(this.lastFilter); - } + /** + * Retrieve a shuffle item by its element. + * @param {Element} element Element to look for. + * @return {?ShuffleItem} A shuffle item or undefined if it's not found. + */ + + }, { + key: 'getItemByElement', + value: function getItemByElement(element) { + return this.items.find(function (item) { + return item.element === element; + }); + } - /** - * Destroys shuffle, removes events, styles, and classes - */ + /** + * Dump the elements currently stored and reinitialize all child elements which + * match the `itemSelector`. + */ - }, { - key: 'destroy', - value: function destroy() { - this._cancelMovement(); - window.removeEventListener('resize', this._onResize); + }, { + key: 'resetItems', + value: function resetItems() { + var _this11 = this; - // Reset container styles - this.element.classList.remove('shuffle'); - this.element.removeAttribute('style'); + // Remove refs to current items. + this._disposeItems(this.items); + this.isInitialized = false; - // Reset individual item styles - this._disposeItems(this.items); + // Find new items in the DOM. + this.items = this._getItems(); - this.items.length = 0; - this._transitions.length = 0; + // Set initial styles on the new items. + this._initItems(this.items); - // Null DOM references - this.options.sizer = null; - this.element = null; + this.once(Shuffle.EventType.LAYOUT, function () { + // Add transition to each item. + _this11.setItemTransitions(_this11.items); + _this11.isInitialized = true; + }); - // Set a flag so if a debounced resize has been triggered, - // it can first check if it is actually isDestroyed and not doing anything - this.isDestroyed = true; - this.isEnabled = false; - } + // Lay out all items. + this.filter(this.lastFilter); + } - /** - * Returns the outer width of an element, optionally including its margins. - * - * There are a few different methods for getting the width of an element, none of - * which work perfectly for all Shuffle's use cases. - * - * 1. getBoundingClientRect() `left` and `right` properties. - * - Accounts for transform scaled elements, making it useless for Shuffle - * elements which have shrunk. - * 2. The `offsetWidth` property. - * - This value stays the same regardless of the elements transform property, - * however, it does not return subpixel values. - * 3. getComputedStyle() - * - This works great Chrome, Firefox, Safari, but IE<=11 does not include - * padding and border when box-sizing: border-box is set, requiring a feature - * test and extra work to add the padding back for IE and other browsers which - * follow the W3C spec here. - * - * @param {Element} element The element. - * @param {boolean} [includeMargins=false] Whether to include margins. - * @return {{width: number, height: number}} The width and height. - */ + /** + * Destroys shuffle, removes events, styles, and classes + */ - }], [{ - key: 'getSize', - value: function getSize(element) { - var includeMargins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - // Store the styles so that they can be used by others without asking for it again. - var styles = window.getComputedStyle(element, null); - var width = getNumberStyle(element, 'width', styles); - var height = getNumberStyle(element, 'height', styles); - - if (includeMargins) { - var marginLeft = getNumberStyle(element, 'marginLeft', styles); - var marginRight = getNumberStyle(element, 'marginRight', styles); - var marginTop = getNumberStyle(element, 'marginTop', styles); - var marginBottom = getNumberStyle(element, 'marginBottom', styles); - width += marginLeft + marginRight; - height += marginTop + marginBottom; - } - - return { - width: width, - height: height - }; - } + }, { + key: 'destroy', + value: function destroy() { + this._cancelMovement(); + window.removeEventListener('resize', this._onResize); - /** - * Change a property or execute a function which will not have a transition - * @param {Element[]} elements DOM elements that won't be transitioned. - * @param {function} callback A function which will be called while transition - * is set to 0ms. - * @private - */ + // Reset container styles + this.element.classList.remove('shuffle'); + this.element.removeAttribute('style'); - }, { - key: '_skipTransitions', - value: function _skipTransitions(elements, callback) { - var zero = '0ms'; + // Reset individual item styles + this._disposeItems(this.items); - // Save current duration and delay. - var data = elements.map(function (element) { - var style = element.style; + this.items.length = 0; + this._transitions.length = 0; - var duration = style.transitionDuration; - var delay = style.transitionDelay; + // Null DOM references + this.options.sizer = null; + this.element = null; - // Set the duration to zero so it happens immediately - style.transitionDuration = zero; - style.transitionDelay = zero; + // Set a flag so if a debounced resize has been triggered, + // it can first check if it is actually isDestroyed and not doing anything + this.isDestroyed = true; + this.isEnabled = false; + } + + /** + * Returns the outer width of an element, optionally including its margins. + * + * There are a few different methods for getting the width of an element, none of + * which work perfectly for all Shuffle's use cases. + * + * 1. getBoundingClientRect() `left` and `right` properties. + * - Accounts for transform scaled elements, making it useless for Shuffle + * elements which have shrunk. + * 2. The `offsetWidth` property. + * - This value stays the same regardless of the elements transform property, + * however, it does not return subpixel values. + * 3. getComputedStyle() + * - This works great Chrome, Firefox, Safari, but IE<=11 does not include + * padding and border when box-sizing: border-box is set, requiring a feature + * test and extra work to add the padding back for IE and other browsers which + * follow the W3C spec here. + * + * @param {Element} element The element. + * @param {boolean} [includeMargins=false] Whether to include margins. + * @return {{width: number, height: number}} The width and height. + */ + + }], [{ + key: 'getSize', + value: function getSize(element) { + var includeMargins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + // Store the styles so that they can be used by others without asking for it again. + var styles = window.getComputedStyle(element, null); + var width = getNumberStyle(element, 'width', styles); + var height = getNumberStyle(element, 'height', styles); + + if (includeMargins) { + var marginLeft = getNumberStyle(element, 'marginLeft', styles); + var marginRight = getNumberStyle(element, 'marginRight', styles); + var marginTop = getNumberStyle(element, 'marginTop', styles); + var marginBottom = getNumberStyle(element, 'marginBottom', styles); + width += marginLeft + marginRight; + height += marginTop + marginBottom; + } return { - duration: duration, - delay: delay + width: width, + height: height }; - }); + } - callback(); + /** + * Change a property or execute a function which will not have a transition + * @param {Element[]} elements DOM elements that won't be transitioned. + * @param {function} callback A function which will be called while transition + * is set to 0ms. + * @private + */ + + }, { + key: '_skipTransitions', + value: function _skipTransitions(elements, callback) { + var zero = '0ms'; + + // Save current duration and delay. + var data = elements.map(function (element) { + var style = element.style; + + var duration = style.transitionDuration; + var delay = style.transitionDelay; + + // Set the duration to zero so it happens immediately + style.transitionDuration = zero; + style.transitionDelay = zero; + + return { + duration: duration, + delay: delay + }; + }); - // Cause forced synchronous layout. - elements[0].offsetWidth; // eslint-disable-line no-unused-expressions + callback(); - // Put the duration back - elements.forEach(function (element, i) { - element.style.transitionDuration = data[i].duration; - element.style.transitionDelay = data[i].delay; - }); - } - }]); - return Shuffle; -}(tinyEmitter); + // Cause forced synchronous layout. + elements[0].offsetWidth; // eslint-disable-line no-unused-expressions + + // Put the duration back + elements.forEach(function (element, i) { + element.style.transitionDuration = data[i].duration; + element.style.transitionDelay = data[i].delay; + }); + } + }]); + return Shuffle; + }(tinyEmitter); -Shuffle.ShuffleItem = ShuffleItem; + Shuffle.ShuffleItem = ShuffleItem; -Shuffle.ALL_ITEMS = 'all'; -Shuffle.FILTER_ATTRIBUTE_KEY = 'groups'; + Shuffle.ALL_ITEMS = 'all'; + Shuffle.FILTER_ATTRIBUTE_KEY = 'groups'; -/** @enum {string} */ -Shuffle.EventType = { - LAYOUT: 'shuffle:layout', - REMOVED: 'shuffle:removed' -}; + /** @enum {string} */ + Shuffle.EventType = { + LAYOUT: 'shuffle:layout', + REMOVED: 'shuffle:removed' + }; -/** @enum {string} */ -Shuffle.Classes = Classes; + /** @enum {string} */ + Shuffle.Classes = Classes; -/** @enum {string} */ -Shuffle.FilterMode = { - ANY: 'any', - ALL: 'all' -}; + /** @enum {string} */ + Shuffle.FilterMode = { + ANY: 'any', + ALL: 'all' + }; -// Overrideable options -Shuffle.options = { - // Initial filter group. - group: Shuffle.ALL_ITEMS, + // Overrideable options + Shuffle.options = { + // Initial filter group. + group: Shuffle.ALL_ITEMS, - // Transition/animation speed (milliseconds). - speed: 250, + // Transition/animation speed (milliseconds). + speed: 250, - // CSS easing function to use. - easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', + // CSS easing function to use. + easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', - // e.g. '.picture-item'. - itemSelector: '*', + // e.g. '.picture-item'. + itemSelector: '*', - // Element or selector string. Use an element to determine the size of columns - // and gutters. - sizer: null, + // Element or selector string. Use an element to determine the size of columns + // and gutters. + sizer: null, - // A static number or function that tells the plugin how wide the gutters - // between columns are (in pixels). - gutterWidth: 0, + // A static number or function that tells the plugin how wide the gutters + // between columns are (in pixels). + gutterWidth: 0, - // A static number or function that returns a number which tells the plugin - // how wide the columns are (in pixels). - columnWidth: 0, + // A static number or function that returns a number which tells the plugin + // how wide the columns are (in pixels). + columnWidth: 0, - // If your group is not json, and is comma delimeted, you could set delimiter - // to ','. - delimiter: null, + // If your group is not json, and is comma delimeted, you could set delimiter + // to ','. + delimiter: null, - // Useful for percentage based heights when they might not always be exactly - // the same (in pixels). - buffer: 0, + // Useful for percentage based heights when they might not always be exactly + // the same (in pixels). + buffer: 0, - // Reading the width of elements isn't precise enough and can cause columns to - // jump between values. - columnThreshold: 0.01, + // Reading the width of elements isn't precise enough and can cause columns to + // jump between values. + columnThreshold: 0.01, - // Shuffle can be isInitialized with a sort object. It is the same object - // given to the sort method. - initialSort: null, + // Shuffle can be isInitialized with a sort object. It is the same object + // given to the sort method. + initialSort: null, - // By default, shuffle will throttle resize events. This can be changed or - // removed. - throttle: throttleit, + // By default, shuffle will throttle resize events. This can be changed or + // removed. + throttle: throttleit, - // How often shuffle can be called on resize (in milliseconds). - throttleTime: 300, + // How often shuffle can be called on resize (in milliseconds). + throttleTime: 300, - // Transition delay offset for each item in milliseconds. - staggerAmount: 15, + // Transition delay offset for each item in milliseconds. + staggerAmount: 15, - // Maximum stagger delay in milliseconds. - staggerAmountMax: 150, + // Maximum stagger delay in milliseconds. + staggerAmountMax: 150, - // Whether to use transforms or absolute positioning. - useTransforms: true, + // Whether to use transforms or absolute positioning. + useTransforms: true, - // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With "any", - // the element passes the test if any of its groups are in the array. With "all", - // the element only passes if all groups are in the array. - filterMode: Shuffle.FilterMode.ANY, + // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With "any", + // the element passes the test if any of its groups are in the array. With "all", + // the element only passes if all groups are in the array. + filterMode: Shuffle.FilterMode.ANY, - // Attempt to center grid items in each row. - isCentered: false, + // Attempt to center grid items in each row. + isCentered: false, - // Whether to round pixel values used in translate(x, y). This usually avoids - // blurriness. - roundTransforms: true -}; + // Whether to round pixel values used in translate(x, y). This usually avoids + // blurriness. + roundTransforms: true + }; -Shuffle.Point = Point; -Shuffle.Rect = Rect; + Shuffle.Point = Point; + Shuffle.Rect = Rect; -// Expose for testing. Hack at your own risk. -Shuffle.__sorter = sorter; -Shuffle.__getColumnSpan = getColumnSpan; -Shuffle.__getAvailablePositions = getAvailablePositions; -Shuffle.__getShortColumn = getShortColumn; -Shuffle.__getCenteredPositions = getCenteredPositions; + // Expose for testing. Hack at your own risk. + Shuffle.__sorter = sorter; + Shuffle.__getColumnSpan = getColumnSpan; + Shuffle.__getAvailablePositions = getAvailablePositions; + Shuffle.__getShortColumn = getShortColumn; + Shuffle.__getCenteredPositions = getCenteredPositions; -return Shuffle; + return Shuffle; }))); //# sourceMappingURL=shuffle.js.map diff --git a/docs/dist/shuffle.js.map b/docs/dist/shuffle.js.map index 1fb316f..fe2c3b6 100644 --- a/docs/dist/shuffle.js.map +++ b/docs/dist/shuffle.js.map @@ -1 +1 @@ -{"version":3,"file":"shuffle.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/hyphenate.js","../src/shuffle.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n"],"names":["getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","e","createElement","cssText","appendChild","window","getComputedStyle","ret","removeChild","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","randomize","array","n","length","i","Math","floor","random","temp","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","by","sort","valA","valB","undefined","compare","reverse","transitions","eventName","count","uniqueId","cancelTransitionEnd","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","slice","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","setY","shortColumnIndex","setHeight","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","hasOverlap","rowIndex","findIndex","items","includes","splice","concat","map","hyphenate","str","replace","m1","toLowerCase","arrayUnique","Set","Shuffle","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","el","_getElementOption","TypeError","_init","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","nodeType","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_doesPassFilter","call","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","before","k","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","matches","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","data","shuffle","emit","itemPositions","_getNextPositions","after","equals","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","_getItemPosition","getTransformedPositions","_getConcealedItems","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","callbacks","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","allItems","_mergeNewItems","sortedItems","allSortedItemsSet","isNewItem","applyHiddenState","isUpdateLayout","oldItems","getItemByElement","handleLayout","_disposeItems","parentNode","REMOVED","once","find","includeMargins","marginLeft","marginRight","marginTop","marginBottom","zero","duration","delay","TinyEmitter","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"shuffle.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/hyphenate.js","../src/shuffle.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n"],"names":["getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","BASE","SHUFFLE_ITEM","VISIBLE","HIDDEN","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","add","removeAttribute","setAttribute","addClasses","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","Object","keys","key","style","removeClasses","position","visibility","before","opacity","after","transitionDelay","document","body","documentElement","e","createElement","cssText","appendChild","window","getComputedStyle","ret","removeChild","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","randomize","array","n","length","i","Math","floor","random","temp","defaults","reverse","by","compare","sorter","arr","options","opts","assign","original","Array","from","revert","sort","valA","valB","undefined","transitions","eventName","count","uniqueId","cancelTransitionEnd","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","slice","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","setY","shortColumnIndex","setHeight","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","hasOverlap","rowIndex","findIndex","items","includes","splice","concat","map","hyphenate","str","replace","m1","toLowerCase","arrayUnique","Set","Shuffle","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","el","_getElementOption","TypeError","_init","_getItems","sizer","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","nodeType","jquery","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_doesPassFilter","call","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","k","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","matches","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","data","shuffle","emit","itemPositions","_getNextPositions","equals","getStylesForTransition","_getStaggerAmount","isCentered","itemsData","_getItemPosition","getTransformedPositions","_getConcealedItems","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","callbacks","_getTransitionFunction","parallel","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","allItems","_mergeNewItems","sortedItems","allSortedItemsSet","isNewItem","applyHiddenState","isUpdateLayout","oldItems","getItemByElement","handleLayout","_disposeItems","parentNode","REMOVED","once","find","includeMargins","marginLeft","marginRight","marginTop","marginBottom","zero","duration","delay","TinyEmitter","ALL","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file diff --git a/docs/dist/shuffle.min.js.map b/docs/dist/shuffle.min.js.map index 4f71422..5c53804 100644 --- a/docs/dist/shuffle.min.js.map +++ b/docs/dist/shuffle.min.js.map @@ -1 +1 @@ -{"version":3,"file":"shuffle.min.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/layout.js","../src/array-min.js","../src/shuffle.js","../src/hyphenate.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n"],"names":["E","prototype","on","name","callback","ctx","e","this","push","fn","once","self","listener","off","apply","arguments","_","emit","data","slice","call","evtArr","i","len","length","evts","liveEvents","proto","Element","vendor","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","el","selector","nodeType","nodes","parentNode","querySelectorAll","func","wait","args","rtn","timeoutID","last","delta","Date","setTimeout","noop","getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","createElement","cssText","appendChild","ret","window","getComputedStyle","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","removeChild","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","randomize","array","n","Math","floor","random","temp","by","sort","valA","valB","undefined","compare","reverse","transitions","eventName","count","cancelTransitionEnd","removeEventListener","onTransitionEnd","evt","currentTarget","target","addEventListener","arrayMax","max","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","min","ceil","getAvailablePositions","positions","available","getShortColumn","buffer","minPosition","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","rowIndex","findIndex","items","includes","splice","concat","map","arrayUnique","Set","Shuffle","_this","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","_getElementOption","TypeError","_init","TinyEmitter","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_this2","_doesPassFilter","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","before","k","replace","str","m1","toLowerCase","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","_this3","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","shuffle","itemPositions","_getNextPositions","after","equals","_this4","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","itemSize","_this5","_getItemPosition","getTransformedPositions","gridSize","total","span","setY","shortColumnIndex","setHeight","getItemPosition","_getConcealedItems","_this6","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","fns","context","pending","finished","results","maybeDone","err","result","_this8","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","sortedItems","_mergeNewItems","allSortedItemsSet","isNewItem","applyHiddenState","_this9","isUpdateLayout","oldItems","_this10","getItemByElement","_disposeItems","REMOVED","find","_this11","includeMargins","duration","delay","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"shuffle.min.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/layout.js","../src/array-min.js","../src/shuffle.js","../src/hyphenate.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst { width } = window.getComputedStyle(e, null);\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(\n element, style,\n styles = window.getComputedStyle(element, null),\n) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // Custom sort function\n compare: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n } else if (typeof opts.compare === 'function') {\n arr.sort(opts.compare);\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 10]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({\n itemSize, positions, gridSize, total, threshold, buffer,\n}) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n // Allow misspelling of delimiter since that's how it used to be.\n // Remove in v6.\n if (this.options.delimeter) {\n this.options.delimiter = this.options.delimeter;\n }\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimiter ?\n attr.split(this.options.delimiter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const { speed, easing } = this.options;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k));\n const properties = positionProps.concat(cssProps).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * Combine the current items array with a new one and sort it by DOM order.\n * @param {ShuffleItem[]} items Items to track.\n * @return {ShuffleItem[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n const x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;\n const y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n\n const allItems = this._mergeNewItems(items);\n const sortedItems = sorter(allItems, this.lastSort);\n const allSortedItemsSet = this._filter(this.lastFilter, sortedItems);\n\n const isNewItem = item => items.includes(item);\n const applyHiddenState = (item) => {\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n };\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(allSortedItemsSet.visible);\n allSortedItemsSet.visible.forEach((item, i) => {\n if (isNewItem(item)) {\n item.point = itemPositions[i];\n applyHiddenState(item);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n allSortedItemsSet.hidden.forEach((item) => {\n if (isNewItem(item)) {\n applyHiddenState(item);\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const { style } = element;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimiter\n // to ','.\n delimiter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n\n // Whether to round pixel values used in translate(x, y). This usually avoids\n // blurriness.\n roundTransforms: true,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n"],"names":["E","prototype","on","name","callback","ctx","e","this","push","fn","once","self","listener","off","apply","arguments","_","emit","data","slice","call","evtArr","i","len","length","evts","liveEvents","proto","Element","vendor","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","el","selector","nodeType","nodes","parentNode","querySelectorAll","func","wait","args","rtn","timeoutID","last","delta","Date","setTimeout","noop","getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","createElement","cssText","appendChild","ret","window","getComputedStyle","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","removeChild","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","randomize","array","n","Math","floor","random","temp","by","sort","valA","valB","undefined","compare","reverse","transitions","eventName","count","cancelTransitionEnd","removeEventListener","onTransitionEnd","evt","currentTarget","target","addEventListener","arrayMax","max","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","min","ceil","getAvailablePositions","positions","available","getShortColumn","buffer","minPosition","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","rowIndex","findIndex","items","includes","splice","concat","map","arrayUnique","Set","Shuffle","_this","delimeter","delimiter","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","_getElementOption","TypeError","_init","TinyEmitter","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_this2","_doesPassFilter","attr","getAttribute","FILTER_ATTRIBUTE_KEY","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","cssProps","before","k","replace","str","m1","toLowerCase","properties","join","transitionDuration","transitionTimingFunction","transitionProperty","children","_this3","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","shuffle","itemPositions","_getNextPositions","after","equals","_this4","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","itemSize","_this5","_getItemPosition","getTransformedPositions","gridSize","total","span","setY","shortColumnIndex","setHeight","getItemPosition","_getConcealedItems","_this6","update","styleObject","roundTransforms","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","fns","context","pending","finished","results","maybeDone","err","result","_this8","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","sortedItems","_mergeNewItems","allSortedItemsSet","isNewItem","applyHiddenState","_this9","isUpdateLayout","oldItems","_this10","getItemByElement","_disposeItems","REMOVED","find","_this11","includeMargins","duration","delay","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 6267446..43d3a9c 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,6 @@ "rollup-plugin-commonjs": "^9.1.0", "rollup-plugin-node-resolve": "^3.0.2", "rollup-plugin-uglify": "^3.0.0", - "sinon": "^5.0.0" + "sinon": "^4.4.0" } }