Add sortedItems prop, fix Chrome bug (#351)

pull/353/head
Glen Cheney 3 years ago committed by GitHub
parent 19875b85b8
commit 9f79d9f441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,5 @@
module.exports = { module.exports = {
extends: 'airbnb-base', extends: ['airbnb-base', 'prettier'],
env: { env: {
node: true, node: true,
browser: true, browser: true,

20
dist/shuffle.js vendored

@ -105,6 +105,8 @@
}; };
} }
var tinyEmitter = {exports: {}};
function E () { function E () {
// Keep this empty so it's easier to inherit from // Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
@ -169,9 +171,10 @@
} }
}; };
var tinyEmitter = E; tinyEmitter.exports = E;
var TinyEmitter = E; tinyEmitter.exports.TinyEmitter = E;
tinyEmitter.TinyEmitter = TinyEmitter;
var TinyEmitter = tinyEmitter.exports;
var proto = typeof Element !== 'undefined' ? Element.prototype : {}; var proto = typeof Element !== 'undefined' ? Element.prototype : {};
var vendor = proto.matches var vendor = proto.matches
@ -510,7 +513,12 @@
var e = document.createElement('div'); var e = document.createElement('div');
e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';
element.appendChild(e); element.appendChild(e);
value = window.getComputedStyle(e, null).width === '10px';
var _window$getComputedSt = window.getComputedStyle(e, null),
width = _window$getComputedSt.width; // Fix for issue #314
value = Math.round(getNumber(width)) === 10;
element.removeChild(e); element.removeChild(e);
return value; return value;
}); });
@ -973,6 +981,7 @@
key: "_init", key: "_init",
value: function _init() { value: function _init() {
this.items = this._getItems(); this.items = this._getItems();
this.sortedItems = this.items;
this.options.sizer = this._getElementOption(this.options.sizer); // Add class and invalidate styles this.options.sizer = this._getElementOption(this.options.sizer); // Add class and invalidate styles
this.element.classList.add(Shuffle.Classes.BASE); // Set initial css for each item this.element.classList.add(Shuffle.Classes.BASE); // Set initial css for each item
@ -1815,6 +1824,7 @@
this._resetCols(); this._resetCols();
var items = sorter(this._getFilteredItems(), sortOptions); var items = sorter(this._getFilteredItems(), sortOptions);
this.sortedItems = items;
this._layout(items); // `_layout` always happens after `_shrink`, so it's safe to process the style this._layout(items); // `_layout` always happens after `_shrink`, so it's safe to process the style
// queue here with styles from the shrink method. // queue here with styles from the shrink method.
@ -2151,7 +2161,7 @@
}]); }]);
return Shuffle; return Shuffle;
}(tinyEmitter); }(TinyEmitter);
Shuffle.ShuffleItem = ShuffleItem; Shuffle.ShuffleItem = ShuffleItem;
Shuffle.ALL_ITEMS = 'all'; Shuffle.ALL_ITEMS = 'all';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,42 +1,100 @@
<h2>Changelog<a href="#changelog"></a></h2> <h2>Changelog<a href="#changelog"></a></h2>
<p>For a more detailed changelog, visit <a href="https://github.com/Vestride/Shuffle/releases">the latest releases</a> on GitHub.</p> <p>
For a more detailed changelog, visit <a href="https://github.com/Vestride/Shuffle/releases">the latest releases</a> on
GitHub.
</p>
<ul> <ul>
<li>
<code>v5.4.0</code> 2021-05-29 - Add <code>sortedItems</code> property. Fix <code>getComputedStyle</code> bug for
Chrome on Windows.
</li>
<li><code>v5.3.0</code> 2021-03-23 - Add <code>isRTL</code> option.</li> <li><code>v5.3.0</code> 2021-03-23 - Add <code>isRTL</code> option.</li>
<li><code>v5.2.3</code> 2019-08-29 - Add missing inherited methods from <code>TinyEmitter</code> to TypeScript definitions.</li> <li>
<code>v5.2.3</code> 2019-08-29 - Add missing inherited methods from <code>TinyEmitter</code> to TypeScript
definitions.
</li>
<li><code>v5.2.2</code> 2019-06-03 - Update TypeScript definitions.</li> <li><code>v5.2.2</code> 2019-06-03 - Update TypeScript definitions.</li>
<li><code>v5.2.1</code> 2018-12-01 - Change `index.d.ts` to use `export default Shuffle` (<a href="https://github.com/Vestride/Shuffle/issues/214#issuecomment-441409237">#214</a>). Upgrade dev dependencies.</li> <li>
<li><code>v5.2.0</code> 2018-08-19 - Lazily test whether the browser's <code>getComputedStyle</code> includes padding. This allows the bundled file to be imported in node for server side rendering.</li> <code>v5.2.1</code> 2018-12-01 - Change `index.d.ts` to use `export default Shuffle` (<a
<li><code>v5.1.2</code> 2018-03-26 - Fix misspelled <code>delimiter</code> option. Both "delimiter" and "delimeter" will continue to work for v5.</li> href="https://github.com/Vestride/Shuffle/issues/214#issuecomment-441409237"
>#214</a
>). Upgrade dev dependencies.
</li>
<li>
<code>v5.2.0</code> 2018-08-19 - Lazily test whether the browser's <code>getComputedStyle</code> includes padding.
This allows the bundled file to be imported in node for server side rendering.
</li>
<li>
<code>v5.1.2</code> 2018-03-26 - Fix misspelled <code>delimiter</code> option. Both "delimiter" and "delimeter" will
continue to work for v5.
</li>
<li><code>v5.1.1</code> 2018-03-02 - Fix new item animation when there is an active filter.</li> <li><code>v5.1.1</code> 2018-03-02 - Fix new item animation when there is an active filter.</li>
<li><code>v5.1.0</code> 2018-02-20 - Add <code>compare</code> option to sorter. Add <code>es</code> build to package and <code>"module"</code> field to <code>package.json</code>.</li> <li>
<code>v5.1.0</code> 2018-02-20 - Add <code>compare</code> option to sorter. Add <code>es</code> build to package and
<code>"module"</code> field to <code>package.json</code>.
</li>
<li><code>v5.0.3</code> 2017-10-30 - Fix rounding error.</li> <li><code>v5.0.3</code> 2017-10-30 - Fix rounding error.</li>
<li><code>v5.0.2</code> 2017-09-23 - Update type definitions. Upgrade dev dependencies.</li> <li><code>v5.0.2</code> 2017-09-23 - Update type definitions. Upgrade dev dependencies.</li>
<li><code>v5.0.1</code> 2017-07-18 - Add <code>roundTransforms</code> option.</li> <li><code>v5.0.1</code> 2017-07-18 - Add <code>roundTransforms</code> option.</li>
<li><code>v5.0.0</code> 2017-07-18 - Change global export from <code>shuffle</code> to <code>Shuffle</code>. Remove bower support. Expect ES6 environment. Make Shuffle instances Event Emitters instead of dispatching <code>CustomEvent</code>.</li> <li>
<li><code>v4.2.0</code> 2017-05-10 - Replace <code>webpack</code> build with <code>rollup</code>. Replace <code>jshint</code> and <code>jscs</code> with <code>eslint</code>. Add <code>filterMode</code> option.</li> <code>v5.0.0</code> 2017-07-18 - Change global export from <code>shuffle</code> to <code>Shuffle</code>. Remove
<li><code>v4.1.1</code> 2017-03-21 - the <code>before</code> styles for a <code>ShuffleItem</code> were not applied if the item didn&rsquo;t move.</li> bower support. Expect ES6 environment. Make Shuffle instances Event Emitters instead of dispatching
<code>CustomEvent</code>.
</li>
<li>
<code>v4.2.0</code> 2017-05-10 - Replace <code>webpack</code> build with <code>rollup</code>. Replace
<code>jshint</code> and <code>jscs</code> with <code>eslint</code>. Add <code>filterMode</code> option.
</li>
<li>
<code>v4.1.1</code> 2017-03-21 - the <code>before</code> styles for a <code>ShuffleItem</code> were not applied if
the item didn&rsquo;t move.
</li>
<li><code>v4.1.0</code> 2017-01-30 - Use webpack-2 to bundle Shuffle.</li> <li><code>v4.1.0</code> 2017-01-30 - Use webpack-2 to bundle Shuffle.</li>
<li><code>v4.0.2</code> 2016-09-15 - Update <code>custom-event-polyfill</code> dependency.</li> <li><code>v4.0.2</code> 2016-09-15 - Update <code>custom-event-polyfill</code> dependency.</li>
<li><code>v4.0.1</code> 2016-07-30 - Fix <code>delimiter</code> option.</li> <li><code>v4.0.1</code> 2016-07-30 - Fix <code>delimiter</code> option.</li>
<li><code>v4.0.0</code> 2016-04-20 - Rewrite in ES6 with babel. Remove jQuery and Modernizr dependencies. Remove support for IE&lt;11. Docs improvements. Switch to gulp build system with webpack.</li> <li>
<li><code>v3.1.0</code> 2015-03-23 - Allow zero speed option (<a href="https://github.com/Vestride/Shuffle/issues/64">#64</a>) and cancel previous animations instead of ignoring new ones (<a href="https://github.com/Vestride/Shuffle/issues/69">#69</a>). Handle non-integer columns better (<a href="https://github.com/Vestride/Shuffle/issues/46">#46</a>)</li> <code>v4.0.0</code> 2016-04-20 - Rewrite in ES6 with babel. Remove jQuery and Modernizr dependencies. Remove support
for IE&lt;11. Docs improvements. Switch to gulp build system with webpack.
</li>
<li>
<code>v3.1.0</code> 2015-03-23 - Allow zero speed option (<a href="https://github.com/Vestride/Shuffle/issues/64"
>#64</a
>) and cancel previous animations instead of ignoring new ones (<a
href="https://github.com/Vestride/Shuffle/issues/69"
>#69</a
>). Handle non-integer columns better (<a href="https://github.com/Vestride/Shuffle/issues/46">#46</a>)
</li>
<li><code>v3.0.4</code> 2015-02-16 - Publish to NPM.</li> <li><code>v3.0.4</code> 2015-02-16 - Publish to NPM.</li>
<li><code>v3.0.2</code> 2015-01-21 - Remove from jQuery plugins directory.</li> <li><code>v3.0.2</code> 2015-01-21 - Remove from jQuery plugins directory.</li>
<li><code>v3.0.1</code> 2014-12-29 - Add CommonJS support.</li> <li><code>v3.0.1</code> 2014-12-29 - Add CommonJS support.</li>
<li><code>v3.0.0</code> 2014-10-06 - Refactored with improvements, added unit tests, more documentation. Removed some triggered events.</li> <li>
<li><code>v2.1.2</code> 2014-06-01 - Use <code>window.jQuery</code> instead of <code>window.$</code> to work better with noConflict. Fixed <a href="https://github.com/Vestride/Shuffle/issues/25">#25</a>.</li> <code>v3.0.0</code> 2014-10-06 - Refactored with improvements, added unit tests, more documentation. Removed some
triggered events.
</li>
<li>
<code>v2.1.2</code> 2014-06-01 - Use <code>window.jQuery</code> instead of <code>window.$</code> to work better with
noConflict. Fixed <a href="https://github.com/Vestride/Shuffle/issues/25">#25</a>.
</li>
<li><code>v2.1.1</code> 2014-04-16 - Fix items with zero opacity overlapping visible ones in IE&lt;10.</li> <li><code>v2.1.1</code> 2014-04-16 - Fix items with zero opacity overlapping visible ones in IE&lt;10.</li>
<li><code>v2.1.0</code> 2014-04-12 - Register with bower as <code>shufflejs</code>.</li> <li><code>v2.1.0</code> 2014-04-12 - Register with bower as <code>shufflejs</code>.</li>
<li>2014-04-10 - Add AMD support.</li> <li>2014-04-10 - Add AMD support.</li>
<li>2014-04-08 - Separate Modernizr into its own file and custom Shuffle build.</li> <li>2014-04-08 - Separate Modernizr into its own file and custom Shuffle build.</li>
<li>2014-03-08 - Add Bootstrap 3 demo. Fixed issue with percentage width items.</li> <li>2014-03-08 - Add Bootstrap 3 demo. Fixed issue with percentage width items.</li>
<li>2013-10-04 - Moved some Shuffle instance properties to constants. Converted from 4 to 2 space indentation. Added events enum and pulled out some strings to constants.</li> <li>
2013-10-04 - Moved some Shuffle instance properties to constants. Converted from 4 to 2 space indentation. Added
events enum and pulled out some strings to constants.
</li>
<li>2013-08-30 - Added animate-in demo.</li> <li>2013-08-30 - Added animate-in demo.</li>
<li><code>v2.0.0</code> 2013-07-05 - Shuffle 2.0 with masonry, adding and removing, and more.</li> <li><code>v2.0.0</code> 2013-07-05 - Shuffle 2.0 with masonry, adding and removing, and more.</li>
<li>2012-11-03 - Replaced layout system with <a href="http://masonry.desandro.com/">masonry</a>. Items can now be different sizes! Added addtional examples.</li> <li>
2012-11-03 - Replaced layout system with <a href="http://masonry.desandro.com/">masonry</a>. Items can now be
different sizes! Added addtional examples.
</li>
<li>2012-10-24 - Better handling of grid item dimensions. Added a minimal markup page.</li> <li>2012-10-24 - Better handling of grid item dimensions. Added a minimal markup page.</li>
<li>2012-09-20 - Added <code>destroy</code> method</li> <li>2012-09-20 - Added <code>destroy</code> method</li>
<li>2012-09-18 - Added sorting ability and made plugin responsive. Updated to Modernizr 2.6.2</li> <li>2012-09-18 - Added sorting ability and made plugin responsive. Updated to Modernizr 2.6.2</li>
<li>2012-07-21 - Rewrote plugin in more object oriented structure. Added custom events. Updated to Modernizr 2.6.1</li> <li>
2012-07-21 - Rewrote plugin in more object oriented structure. Added custom events. Updated to Modernizr 2.6.1
</li>
<li>2012-07-03 - Removed dependency on the css file and now apply the css with javascript</li> <li>2012-07-03 - Removed dependency on the css file and now apply the css with javascript</li>
</ul> </ul>

@ -1 +1 @@
.picture-item{height:220px;margin-top:24px;margin-left:0}.picture-item img{display:block;width:100%}@supports ((-o-object-fit: cover) or (object-fit: cover)){.picture-item img{max-width:none;height:100%;-o-object-fit:cover;object-fit:cover}}.picture-item--h2{height:464px}.picture-item__inner{position:relative;height:100%;overflow:hidden;background:#ecf0f1}img.picture-item__blur{display:none}.picture-item__details{display:flex;align-items:baseline;justify-content:space-between;width:100%;padding:1em}.picture-item__description{width:100%;padding:0 2em 1em 1em;margin:0}.picture-item__title{flex-shrink:0;margin-right:4px}.picture-item__tags{flex-shrink:1;text-align:right;margin:0}@media screen and (min-width:768px){.picture-item--overlay .picture-item__details{position:absolute;bottom:0;left:0;width:100%;background-color:rgba(0,0,0,.6);color:#fff;overflow:hidden}.picture-item--overlay .picture-item__description{display:none}@supports (filter:blur(1px)) and ((-webkit-clip-path: inset(0 0 0 0)) or (clip-path: inset(0 0 0 0))){.picture-item--overlay .picture-item__blur{position:absolute;z-index:1;top:0;left:0;display:block;filter:blur(7px);-webkit-clip-path:inset(170px 0 0 0);clip-path:inset(170px 0 0 0)}.picture-item--overlay .picture-item__details{background:none}.picture-item--overlay .picture-item__tags,.picture-item--overlay .picture-item__title{position:relative;z-index:2}}}.my-shuffle-container{position:relative;overflow:hidden}.my-sizer-element{position:absolute;opacity:0;visibility:hidden}.shuffle--animatein{overflow:visible}.shuffle--animatein .picture-item__inner{opacity:0;transform:translateY(220px)}.shuffle--animatein .picture-item__inner--transition{transition:all .6s ease}.shuffle--animatein .picture-item.in .picture-item__inner{opacity:1;transform:translate(0)}@media screen and (max-width:767px){.picture-item{height:auto;margin-top:20px}.picture-item__description,.picture-item__details{font-size:.875em;padding:.625em}.picture-item__description{padding-right:.875em;padding-bottom:1.25em}.picture-item--h2{height:auto}} .picture-item{height:220px;margin-left:0;margin-top:24px}.picture-item img{display:block;width:100%}@supports ((-o-object-fit:cover) or (object-fit:cover)){.picture-item img{height:100%;max-width:none;-o-object-fit:cover;object-fit:cover}}.picture-item--h2{height:464px}.picture-item__inner{background:#ecf0f1;height:100%;overflow:hidden;position:relative}img.picture-item__blur{display:none}.picture-item__details{align-items:baseline;display:flex;justify-content:space-between;padding:1em;width:100%}.picture-item__description{margin:0;padding:0 2em 1em 1em;width:100%}.picture-item__title{flex-shrink:0;margin-right:4px}.picture-item__tags{flex-shrink:1;margin:0;text-align:right}@media screen and (min-width:768px){.picture-item--overlay .picture-item__details{background-color:rgba(0,0,0,.6);bottom:0;color:#fff;left:0;overflow:hidden;position:absolute;width:100%}.picture-item--overlay .picture-item__description{display:none}@supports (filter:blur(1px)) and ((-webkit-clip-path:inset(0 0 0 0)) or (clip-path:inset(0 0 0 0))){.picture-item--overlay .picture-item__blur{-webkit-clip-path:inset(170px 0 0 0);clip-path:inset(170px 0 0 0);display:block;filter:blur(7px);left:0;position:absolute;top:0;z-index:1}.picture-item--overlay .picture-item__details{background:none}.picture-item--overlay .picture-item__tags,.picture-item--overlay .picture-item__title{position:relative;z-index:2}}}.my-shuffle-container{overflow:hidden;position:relative}.my-sizer-element{opacity:0;position:absolute;visibility:hidden}.shuffle--animatein{overflow:visible}.shuffle--animatein .picture-item__inner{opacity:0;transform:translateY(220px)}.shuffle--animatein .picture-item__inner--transition{transition:all .6s ease}.shuffle--animatein .picture-item.in .picture-item__inner{opacity:1;transform:translate(0)}@media screen and (max-width:767px){.picture-item{height:auto;margin-top:20px}.picture-item__description,.picture-item__details{font-size:.875em;padding:.625em}.picture-item__description{padding-bottom:1.25em;padding-right:.875em}.picture-item--h2{height:auto}}

File diff suppressed because one or more lines are too long

@ -105,6 +105,8 @@
}; };
} }
var tinyEmitter = {exports: {}};
function E () { function E () {
// Keep this empty so it's easier to inherit from // Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
@ -169,9 +171,10 @@
} }
}; };
var tinyEmitter = E; tinyEmitter.exports = E;
var TinyEmitter = E; tinyEmitter.exports.TinyEmitter = E;
tinyEmitter.TinyEmitter = TinyEmitter;
var TinyEmitter = tinyEmitter.exports;
var proto = typeof Element !== 'undefined' ? Element.prototype : {}; var proto = typeof Element !== 'undefined' ? Element.prototype : {};
var vendor = proto.matches var vendor = proto.matches
@ -510,7 +513,12 @@
var e = document.createElement('div'); var e = document.createElement('div');
e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';
element.appendChild(e); element.appendChild(e);
value = window.getComputedStyle(e, null).width === '10px';
var _window$getComputedSt = window.getComputedStyle(e, null),
width = _window$getComputedSt.width; // Fix for issue #314
value = Math.round(getNumber(width)) === 10;
element.removeChild(e); element.removeChild(e);
return value; return value;
}); });
@ -973,6 +981,7 @@
key: "_init", key: "_init",
value: function _init() { value: function _init() {
this.items = this._getItems(); this.items = this._getItems();
this.sortedItems = this.items;
this.options.sizer = this._getElementOption(this.options.sizer); // Add class and invalidate styles this.options.sizer = this._getElementOption(this.options.sizer); // Add class and invalidate styles
this.element.classList.add(Shuffle.Classes.BASE); // Set initial css for each item this.element.classList.add(Shuffle.Classes.BASE); // Set initial css for each item
@ -1815,6 +1824,7 @@
this._resetCols(); this._resetCols();
var items = sorter(this._getFilteredItems(), sortOptions); var items = sorter(this._getFilteredItems(), sortOptions);
this.sortedItems = items;
this._layout(items); // `_layout` always happens after `_shrink`, so it's safe to process the style this._layout(items); // `_layout` always happens after `_shrink`, so it's safe to process the style
// queue here with styles from the shrink method. // queue here with styles from the shrink method.
@ -2151,7 +2161,7 @@
}]); }]);
return Shuffle; return Shuffle;
}(tinyEmitter); }(TinyEmitter);
Shuffle.ShuffleItem = ShuffleItem; Shuffle.ShuffleItem = ShuffleItem;
Shuffle.ALL_ITEMS = 'all'; Shuffle.ALL_ITEMS = 'all';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

12
index.d.ts vendored

@ -82,7 +82,7 @@ export interface ShuffleOptions {
/** /**
* Whether to round pixel values used in translate(x, y). This usually avoids blurriness. * Whether to round pixel values used in translate(x, y). This usually avoids blurriness.
*/ */
roundTransforms?: boolean, roundTransforms?: boolean;
/** /**
* Element or selector string. Use an element to determine the size of columns and gutters. * Element or selector string. Use an element to determine the size of columns and gutters.
@ -246,7 +246,7 @@ declare class Shuffle extends TinyEmitter {
* Returns styles which will be applied to the an item for a transition. * Returns styles which will be applied to the an item for a transition.
* @param {object} obj Transition options. * @param {object} obj Transition options.
*/ */
protected getStylesForTransition(obj: { item: Shuffle.ShuffleItem, styles: InlineCssStyles }): InlineCssStyles; protected getStylesForTransition(obj: { item: Shuffle.ShuffleItem; styles: InlineCssStyles }): InlineCssStyles;
/** /**
* Mutate positions before they're applied. * Mutate positions before they're applied.
@ -293,8 +293,12 @@ declare class Shuffle extends TinyEmitter {
/** Whether items are currently transitioning */ /** Whether items are currently transitioning */
isTransitioning: boolean; isTransitioning: boolean;
/** ShuffleItems being kept track of */ /** ShuffleItems being kept track of, sorted in DOM order. */
items: Shuffle.ShuffleItem[]; items: Shuffle.ShuffleItem[];
/** Visible ShuffleItems being tracked, sorted in the current sort order */
sortedItems: Shuffle.ShuffleItem[];
lastFilter: FilterArg; lastFilter: FilterArg;
lastSort: SortOptions; lastSort: SortOptions;
@ -312,7 +316,7 @@ declare class Shuffle extends TinyEmitter {
* @param {HTMLElement} element The element. * @param {HTMLElement} element The element.
* @param {boolean} [includeMargins=false] Whether to include margins. * @param {boolean} [includeMargins=false] Whether to include margins.
*/ */
static getSize(element: HTMLElement, includeMargins?: boolean): {width: number, height: number}; static getSize(element: HTMLElement, includeMargins?: boolean): { width: number; height: number };
} }
declare namespace Shuffle { declare namespace Shuffle {

@ -58,6 +58,7 @@
"cssnano": "^5.0.4", "cssnano": "^5.0.4",
"eslint": "^7.5.0", "eslint": "^7.5.0",
"eslint-config-airbnb-base": "^14.0.0", "eslint-config-airbnb-base": "^14.0.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.17.3", "eslint-plugin-import": "^2.17.3",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-postcss": "^9.0.0", "gulp-postcss": "^9.0.0",

@ -1,3 +1,5 @@
import getNumber from './get-number';
let value = null; let value = null;
export default () => { export default () => {
if (value !== null) { if (value !== null) {
@ -9,7 +11,9 @@ export default () => {
e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';
element.appendChild(e); element.appendChild(e);
value = window.getComputedStyle(e, null).width === '10px'; const { width } = window.getComputedStyle(e, null);
// Fix for issue #314
value = Math.round(getNumber(width)) === 10;
element.removeChild(e); element.removeChild(e);

@ -10,13 +10,7 @@ import Classes from './classes';
import getNumberStyle from './get-number-style'; import getNumberStyle from './get-number-style';
import sorter from './sorter'; import sorter from './sorter';
import { onTransitionEnd, cancelTransitionEnd } from './on-transition-end'; import { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';
import { import { getItemPosition, getColumnSpan, getAvailablePositions, getShortColumn, getCenteredPositions } from './layout';
getItemPosition,
getColumnSpan,
getAvailablePositions,
getShortColumn,
getCenteredPositions,
} from './layout';
import arrayMax from './array-max'; import arrayMax from './array-max';
import hyphenate from './hyphenate'; import hyphenate from './hyphenate';
@ -72,6 +66,7 @@ class Shuffle extends TinyEmitter {
_init() { _init() {
this.items = this._getItems(); this.items = this._getItems();
this.sortedItems = this.items;
this.options.sizer = this._getElementOption(this.options.sizer); this.options.sizer = this._getElementOption(this.options.sizer);
@ -126,9 +121,7 @@ class Shuffle extends TinyEmitter {
*/ */
_getResizeFunction() { _getResizeFunction() {
const resizeFunction = this._handleResize.bind(this); const resizeFunction = this._handleResize.bind(this);
return this.options.throttle return this.options.throttle ? this.options.throttle(resizeFunction, this.options.throttleTime) : resizeFunction;
? this.options.throttle(resizeFunction, this.options.throttleTime)
: resizeFunction;
} }
/** /**
@ -216,8 +209,8 @@ class Shuffle extends TinyEmitter {
if (category === Shuffle.ALL_ITEMS) { if (category === Shuffle.ALL_ITEMS) {
visible = items; visible = items;
// Loop through each item and use provided function to determine // Loop through each item and use provided function to determine
// whether to hide it or not. // whether to hide it or not.
} else { } else {
items.forEach((item) => { items.forEach((item) => {
if (this._doesPassFilter(category, item.element)) { if (this._doesPassFilter(category, item.element)) {
@ -248,9 +241,7 @@ class Shuffle extends TinyEmitter {
// Check each element's data-groups attribute against the given category. // Check each element's data-groups attribute against the given category.
const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY); const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);
const keys = this.options.delimiter const keys = this.options.delimiter ? attr.split(this.options.delimiter) : JSON.parse(attr);
? attr.split(this.options.delimiter)
: JSON.parse(attr);
function testCategory(category) { function testCategory(category) {
return keys.includes(category); return keys.includes(category);
@ -376,19 +367,19 @@ class Shuffle extends TinyEmitter {
if (typeof this.options.columnWidth === 'function') { if (typeof this.options.columnWidth === 'function') {
size = this.options.columnWidth(containerWidth); size = this.options.columnWidth(containerWidth);
// columnWidth option isn't a function, are they using a sizing element? // columnWidth option isn't a function, are they using a sizing element?
} else if (this.options.sizer) { } else if (this.options.sizer) {
size = Shuffle.getSize(this.options.sizer).width; size = Shuffle.getSize(this.options.sizer).width;
// if not, how about the explicitly set option? // if not, how about the explicitly set option?
} else if (this.options.columnWidth) { } else if (this.options.columnWidth) {
size = this.options.columnWidth; size = this.options.columnWidth;
// or use the size of the first item // or use the size of the first item
} else if (this.items.length > 0) { } else if (this.items.length > 0) {
size = Shuffle.getSize(this.items[0].element, true).width; size = Shuffle.getSize(this.items[0].element, true).width;
// if there's no items, use size of container // if there's no items, use size of container
} else { } else {
size = containerWidth; size = containerWidth;
} }
@ -431,8 +422,7 @@ class Shuffle extends TinyEmitter {
let calculatedColumns = (containerWidth + gutter) / columnWidth; let calculatedColumns = (containerWidth + gutter) / columnWidth;
// Widths given from getStyles are not precise enough... // Widths given from getStyles are not precise enough...
if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) < this.options.columnThreshold) {
< this.options.columnThreshold) {
// e.g. calculatedColumns = 11.998876 // e.g. calculatedColumns = 11.998876
calculatedColumns = Math.round(calculatedColumns); calculatedColumns = Math.round(calculatedColumns);
} }
@ -719,9 +709,9 @@ class Shuffle extends TinyEmitter {
this._styleImmediately(this._queue); this._styleImmediately(this._queue);
this._dispatch(Shuffle.EventType.LAYOUT); this._dispatch(Shuffle.EventType.LAYOUT);
// A call to layout happened, but none of the newly visible items will // 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 // change position or the transition duration is zero, which will not trigger
// the transitionend event. // the transitionend event.
} else { } else {
this._dispatch(Shuffle.EventType.LAYOUT); this._dispatch(Shuffle.EventType.LAYOUT);
} }
@ -818,6 +808,7 @@ class Shuffle extends TinyEmitter {
this._resetCols(); this._resetCols();
const items = sorter(this._getFilteredItems(), sortOptions); const items = sorter(this._getFilteredItems(), sortOptions);
this.sortedItems = items;
this._layout(items); this._layout(items);
@ -943,9 +934,7 @@ class Shuffle extends TinyEmitter {
const collection = arrayUnique(elements); const collection = arrayUnique(elements);
const oldItems = collection const oldItems = collection.map((element) => this.getItemByElement(element)).filter((item) => !!item);
.map((element) => this.getItemByElement(element))
.filter((item) => !!item);
const handleLayout = () => { const handleLayout = () => {
this._disposeItems(oldItems); this._disposeItems(oldItems);
@ -1025,6 +1014,7 @@ class Shuffle extends TinyEmitter {
this._disposeItems(this.items); this._disposeItems(this.items);
this.items.length = 0; this.items.length = 0;
this.sortedItems.length = 0;
this._transitions.length = 0; this._transitions.length = 0;
// Null DOM references // Null DOM references

@ -26,4 +26,4 @@ export const delimiter = `
<div class="item" id="item9" data-groups='design,red'>Person 9</div> <div class="item" id="item9" data-groups='design,red'>Person 9</div>
<div class="item" id="item10" data-groups='technology,black'>Person 10</div> <div class="item" id="item10" data-groups='technology,black'>Person 10</div>
</div> </div>
` `;

@ -38,7 +38,6 @@ describe('shuffle', () => {
} }
describe('regular fixture', () => { describe('regular fixture', () => {
beforeEach(() => { beforeEach(() => {
// Mock the transition end event wrapper. // Mock the transition end event wrapper.
sinon.stub(Shuffle.prototype, '_whenTransitionDone').callsFake(whenTransitionDoneStub); sinon.stub(Shuffle.prototype, '_whenTransitionDone').callsFake(whenTransitionDoneStub);
@ -55,6 +54,7 @@ describe('shuffle', () => {
instance = new Shuffle(fixture); instance = new Shuffle(fixture);
expect(instance.items.length).toBe(10); expect(instance.items.length).toBe(10);
expect(instance.visibleItems).toBe(10); expect(instance.visibleItems).toBe(10);
expect(instance.sortedItems).toHaveLength(10);
expect(instance.options.group).toBe('all'); expect(instance.options.group).toBe('all');
expect(instance.options.speed).toBe(250); expect(instance.options.speed).toBe(250);
expect(instance.options.itemSelector).toBe('*'); expect(instance.options.itemSelector).toBe('*');
@ -165,23 +165,23 @@ describe('shuffle', () => {
expect(instance.positions).toEqual([40, 40, 30, 30]); expect(instance.positions).toEqual([40, 40, 30, 30]);
}); });
it('can filter by the data attribute', done => { it('can filter by the data attribute', (done) => {
instance = new Shuffle(fixture, { instance = new Shuffle(fixture, {
speed: 0, speed: 0,
}); });
function second() { function second() {
expect(instance.visibleItems).toBe(3); expect(instance.visibleItems).toBe(3);
const hidden = [3, 4, 5, 6, 7, 8, 10].map(num => id(`item${num}`)); const hidden = [3, 4, 5, 6, 7, 8, 10].map((num) => id(`item${num}`));
const visible = [1, 2, 9].map(num => id(`item${num}`)); const visible = [1, 2, 9].map((num) => id(`item${num}`));
hidden.forEach(element => { hidden.forEach((element) => {
expect(element.classList.contains(Shuffle.Classes.HIDDEN)).toBe(true); expect(element.classList.contains(Shuffle.Classes.HIDDEN)).toBe(true);
expect(element.style.visibility).toBe('hidden'); expect(element.style.visibility).toBe('hidden');
}); });
visible.forEach(element => { visible.forEach((element) => {
expect(element.classList.contains(Shuffle.Classes.VISIBLE)).toBe(true); expect(element.classList.contains(Shuffle.Classes.VISIBLE)).toBe(true);
expect(element.style.visibility).toBe('visible'); expect(element.style.visibility).toBe('visible');
}); });
@ -194,16 +194,16 @@ describe('shuffle', () => {
function third() { function third() {
expect(instance.visibleItems).toBe(2); expect(instance.visibleItems).toBe(2);
const hidden = [1, 2, 5, 6, 7, 8, 9, 10].map(num => id(`item${num}`)); const hidden = [1, 2, 5, 6, 7, 8, 9, 10].map((num) => id(`item${num}`));
const visible = [3, 4].map(num => id(`item${num}`)); const visible = [3, 4].map((num) => id(`item${num}`));
hidden.forEach(element => { hidden.forEach((element) => {
expect(element.classList.contains(Shuffle.Classes.HIDDEN)).toBe(true); expect(element.classList.contains(Shuffle.Classes.HIDDEN)).toBe(true);
expect(element.style.visibility).toBe('hidden'); expect(element.style.visibility).toBe('hidden');
}); });
visible.forEach(element => { visible.forEach((element) => {
expect(element.classList.contains(Shuffle.Classes.VISIBLE)).toBe(true); expect(element.classList.contains(Shuffle.Classes.VISIBLE)).toBe(true);
expect(element.style.visibility).toBe('visible'); expect(element.style.visibility).toBe('visible');
}); });
@ -264,15 +264,20 @@ describe('shuffle', () => {
it('can center already-positioned items', () => { it('can center already-positioned items', () => {
// 4-2-1 even heights // 4-2-1 even heights
expect(Shuffle.__getCenteredPositions([ expect(
new Shuffle.Rect(0, 0, 250, 100, 0), Shuffle.__getCenteredPositions(
new Shuffle.Rect(250, 0, 250, 100, 1), [
new Shuffle.Rect(500, 0, 250, 100, 2), new Shuffle.Rect(0, 0, 250, 100, 0),
new Shuffle.Rect(750, 0, 250, 100, 3), new Shuffle.Rect(250, 0, 250, 100, 1),
new Shuffle.Rect(0, 100, 600, 100, 4), new Shuffle.Rect(500, 0, 250, 100, 2),
new Shuffle.Rect(600, 100, 300, 100, 5), new Shuffle.Rect(750, 0, 250, 100, 3),
new Shuffle.Rect(0, 200, 250, 100, 6), new Shuffle.Rect(0, 100, 600, 100, 4),
], 1000)).toEqual([ new Shuffle.Rect(600, 100, 300, 100, 5),
new Shuffle.Rect(0, 200, 250, 100, 6),
],
1000,
),
).toEqual([
new Shuffle.Point(0, 0), new Shuffle.Point(0, 0),
new Shuffle.Point(250, 0), new Shuffle.Point(250, 0),
new Shuffle.Point(500, 0), new Shuffle.Point(500, 0),
@ -287,15 +292,16 @@ describe('shuffle', () => {
// 2x1 // 2x1
// Centers the first row, but then finds that the 3rd item will overlap // Centers the first row, but then finds that the 3rd item will overlap
// the 2x2 and resets the first row. // the 2x2 and resets the first row.
expect(Shuffle.__getCenteredPositions([ expect(
new Shuffle.Rect(0, 0, 500, 200, 0), Shuffle.__getCenteredPositions(
new Shuffle.Rect(500, 0, 250, 100, 1), [
new Shuffle.Rect(500, 100, 500, 100, 2), new Shuffle.Rect(0, 0, 500, 200, 0),
], 1000)).toEqual([ new Shuffle.Rect(500, 0, 250, 100, 1),
new Shuffle.Point(0, 0), new Shuffle.Rect(500, 100, 500, 100, 2),
new Shuffle.Point(500, 0), ],
new Shuffle.Point(500, 100), 1000,
]); ),
).toEqual([new Shuffle.Point(0, 0), new Shuffle.Point(500, 0), new Shuffle.Point(500, 100)]);
}); });
it('can get an element option', () => { it('can get an element option', () => {
@ -317,12 +323,14 @@ describe('shuffle', () => {
expect(instance._doesPassFilter('design', first)).toBe(true); expect(instance._doesPassFilter('design', first)).toBe(true);
expect(instance._doesPassFilter('black', first)).toBe(false); expect(instance._doesPassFilter('black', first)).toBe(false);
expect(instance._doesPassFilter(element => { expect(
expect(element).toBeDefined(); instance._doesPassFilter((element) => {
return element.getAttribute('data-age') === '21'; expect(element).toBeDefined();
}, first)).toBe(true); return element.getAttribute('data-age') === '21';
}, first),
).toBe(true);
expect(instance._doesPassFilter(element => element.getAttribute('data-age') === '22', first)).toBe(false); expect(instance._doesPassFilter((element) => element.getAttribute('data-age') === '22', first)).toBe(false);
// Arrays. // Arrays.
expect(instance._doesPassFilter(['design'], first)).toBe(true); expect(instance._doesPassFilter(['design'], first)).toBe(true);
@ -348,7 +356,39 @@ describe('shuffle', () => {
instance.sort(); instance.sort();
expect(instance.lastSort).toEqual({ glen: true }); expect(instance.lastSort).toEqual({ glen: true });
});
it('tracks sorted items', () => {
instance = new Shuffle(fixture);
expect(instance.sortedItems.map((item) => item.element.id)).toEqual([
'item1',
'item2',
'item3',
'item4',
'item5',
'item6',
'item7',
'item8',
'item9',
'item10',
]);
instance.sort({
reverse: true,
});
expect(instance.sortedItems.map((item) => item.element.id)).toEqual([
'item10',
'item9',
'item8',
'item7',
'item6',
'item5',
'item4',
'item3',
'item2',
'item1',
]);
}); });
it('should reset columns', () => { it('should reset columns', () => {
@ -376,7 +416,7 @@ describe('shuffle', () => {
expect(fixture.classList.contains('shuffle')).toBe(false); expect(fixture.classList.contains('shuffle')).toBe(false);
Array.from(fixture.children).forEach(child => { Array.from(fixture.children).forEach((child) => {
expect(child.classList.contains('shuffle-item')).toBe(false); expect(child.classList.contains('shuffle-item')).toBe(false);
expect(child.classList.contains('shuffle-item--visible')).toBe(false); expect(child.classList.contains('shuffle-item--visible')).toBe(false);
expect(child.classList.contains('shuffle-item--hidden')).toBe(false); expect(child.classList.contains('shuffle-item--hidden')).toBe(false);
@ -422,7 +462,7 @@ describe('shuffle', () => {
children = null; children = null;
}); });
it('can remove items', done => { it('can remove items', (done) => {
instance = new Shuffle(fixture, { instance = new Shuffle(fixture, {
speed: 16, speed: 16,
}); });
@ -440,7 +480,7 @@ describe('shuffle', () => {
instance.remove(itemsToRemove); instance.remove(itemsToRemove);
}); });
it('can remove items without transforms', done => { it('can remove items without transforms', (done) => {
instance = new Shuffle(fixture, { instance = new Shuffle(fixture, {
speed: 100, speed: 100,
useTransforms: false, useTransforms: false,
@ -517,13 +557,14 @@ describe('shuffle', () => {
items.length = 0; items.length = 0;
}); });
it('can add items', done => { it('can add items', (done) => {
fixture.appendChild(items[0]); fixture.appendChild(items[0]);
fixture.appendChild(items[1]); fixture.appendChild(items[1]);
instance.add(items); instance.add(items);
// Already 2 in the items, plus number 11. // Already 2 in the items, plus number 11.
expect(instance.visibleItems).toBe(3); expect(instance.visibleItems).toBe(3);
expect(instance.sortedItems.map((item) => item.element.id)).toEqual(['item8', 'item10', 'item11']);
expect(instance.items).toHaveLength(12); expect(instance.items).toHaveLength(12);
instance.once(Shuffle.EventType.LAYOUT, () => { instance.once(Shuffle.EventType.LAYOUT, () => {
@ -531,13 +572,14 @@ describe('shuffle', () => {
}); });
}); });
it('can prepend items', done => { it('can prepend items', (done) => {
fixture.insertBefore(items[1], fixture.firstElementChild); fixture.insertBefore(items[1], fixture.firstElementChild);
fixture.insertBefore(items[0], fixture.firstElementChild); fixture.insertBefore(items[0], fixture.firstElementChild);
instance.add(items); instance.add(items);
expect(instance.items[0].element).toBe(items[0]); expect(instance.items[0].element).toBe(items[0]);
expect(instance.items[1].element).toBe(items[1]); expect(instance.items[1].element).toBe(items[1]);
expect(instance.sortedItems.map((item) => item.element.id)).toEqual(['item11', 'item8', 'item10']);
expect(instance.items).toHaveLength(12); expect(instance.items).toHaveLength(12);
instance.once(Shuffle.EventType.LAYOUT, () => { instance.once(Shuffle.EventType.LAYOUT, () => {
@ -557,7 +599,6 @@ describe('shuffle', () => {
expect(instance.items[1].element).toBe(items[1]); expect(instance.items[1].element).toBe(items[1]);
expect(instance.items).toHaveLength(2); expect(instance.items).toHaveLength(2);
}); });
}); });
}); });
@ -611,7 +652,7 @@ describe('shuffle', () => {
// The layout method will have already set styles to their 'after' states // The layout method will have already set styles to their 'after' states
// upon initialization. Reset them here. // upon initialization. Reset them here.
instance.items.forEach(item => { instance.items.forEach((item) => {
item.applyCss(Shuffle.ShuffleItem.Css.INITIAL); item.applyCss(Shuffle.ShuffleItem.Css.INITIAL);
}); });
@ -635,8 +676,8 @@ describe('shuffle', () => {
beforeEach(() => { beforeEach(() => {
appendFixture('regular'); appendFixture('regular');
items = Array.from(fixture.children).map(element => ({ items = Array.from(fixture.children).map((element) => ({
element element,
})); }));
clone = Array.from(items); clone = Array.from(items);
@ -678,11 +719,13 @@ describe('shuffle', () => {
}); });
it('can sort by a function and reverse it', () => { it('can sort by a function and reverse it', () => {
clone.sort((a, b) => { clone
const age1 = parseInt(a.element.getAttribute('data-age'), 10); .sort((a, b) => {
const age2 = parseInt(b.element.getAttribute('data-age'), 10); const age1 = parseInt(a.element.getAttribute('data-age'), 10);
return age1 - age2; const age2 = parseInt(b.element.getAttribute('data-age'), 10);
}).reverse(); return age1 - age2;
})
.reverse();
const result = Shuffle.__sorter(items, { const result = Shuffle.__sorter(items, {
reverse: true, reverse: true,
@ -696,42 +739,48 @@ describe('shuffle', () => {
it('will revert to DOM order if the `by` function returns undefined', () => { it('will revert to DOM order if the `by` function returns undefined', () => {
let count = 0; let count = 0;
expect(Shuffle.__sorter(items, { expect(
by() { Shuffle.__sorter(items, {
count++; by() {
return count < 5 ? Math.random() : undefined; count++;
}, return count < 5 ? Math.random() : undefined;
})).toEqual(clone); },
}),
).toEqual(clone);
}); });
it('can sort things to the top', () => { it('can sort things to the top', () => {
items = items.slice(0, 4); items = items.slice(0, 4);
const final = [items[1], items[0], items[3], items[2]]; const final = [items[1], items[0], items[3], items[2]];
expect(Shuffle.__sorter(items, { expect(
by(element) { Shuffle.__sorter(items, {
const age = parseInt(element.getAttribute('data-age'), 10); by(element) {
if (age === 50) { const age = parseInt(element.getAttribute('data-age'), 10);
return 'sortFirst'; if (age === 50) {
} else { return 'sortFirst';
return age; } else {
} return age;
}, }
})).toEqual(final); },
}),
).toEqual(final);
}); });
it('can sort things to the bottom', () => { it('can sort things to the bottom', () => {
items = items.slice(0, 4); items = items.slice(0, 4);
const final = [items[0], items[2], items[1], items[3]]; const final = [items[0], items[2], items[1], items[3]];
expect(Shuffle.__sorter(items, { expect(
by(element) { Shuffle.__sorter(items, {
const age = parseInt(element.getAttribute('data-age'), 10); by(element) {
if (age === 27) { const age = parseInt(element.getAttribute('data-age'), 10);
return 'sortLast'; if (age === 27) {
} else { return 'sortLast';
return age; } else {
} return age;
}, }
})).toEqual(final); },
}),
).toEqual(final);
}); });
it('can have a custom sort comparator', () => { it('can have a custom sort comparator', () => {
@ -747,25 +796,26 @@ describe('shuffle', () => {
clone[3], // ux, 27 clone[3], // ux, 27
clone[4], // ux, 35 clone[4], // ux, 35
]; ];
expect(Shuffle.__sorter(items, { expect(
compare(a, b) { Shuffle.__sorter(items, {
// Sort by first group, then by age. compare(a, b) {
const groupA = JSON.parse(a.element.getAttribute('data-groups'))[0]; // Sort by first group, then by age.
const groupB = JSON.parse(b.element.getAttribute('data-groups'))[0]; const groupA = JSON.parse(a.element.getAttribute('data-groups'))[0];
if (groupA > groupB) { const groupB = JSON.parse(b.element.getAttribute('data-groups'))[0];
return 1; if (groupA > groupB) {
} return 1;
if (groupA < groupB) { }
return -1; if (groupA < groupB) {
} return -1;
}
// At this point, the group strings are the exact same. Test the age.
const ageA = parseInt(a.element.getAttribute('data-age'), 10); // At this point, the group strings are the exact same. Test the age.
const ageB = parseInt(b.element.getAttribute('data-age'), 10); const ageA = parseInt(a.element.getAttribute('data-age'), 10);
return ageA - ageB; const ageB = parseInt(b.element.getAttribute('data-age'), 10);
}, return ageA - ageB;
})).toEqual(final); },
}),
).toEqual(final);
}); });
}); });
}); });

@ -9,12 +9,7 @@ if (!mainElement) {
throw new TypeError('oopsie'); throw new TypeError('oopsie');
} }
console.log( console.log(Shuffle.EventType.LAYOUT, Shuffle.Classes.SHUFFLE_ITEM, Shuffle.FilterMode.ALL, Shuffle.ShuffleItem.Css);
Shuffle.EventType.LAYOUT,
Shuffle.Classes.SHUFFLE_ITEM,
Shuffle.FilterMode.ALL,
Shuffle.ShuffleItem.Css,
);
const options: ShuffleOptions = { const options: ShuffleOptions = {
buffer: 0, buffer: 0,
@ -49,6 +44,7 @@ const sortOptions: SortOptions = {
}, },
}; };
shuffle.sort(sortOptions); shuffle.sort(sortOptions);
console.log(shuffle.sortedItems);
shuffle.update(true); shuffle.update(true);
Shuffle.getSize(mainElement, true); Shuffle.getSize(mainElement, true);

Loading…
Cancel
Save