├── bin
├── lint-json.js
├── .eslintrc.js
├── version.js
└── bundle-js.js
├── .gitignore
├── .jshintrc
├── test
├── unit
│ ├── helpers.js
│ ├── masonry-stamp.js
│ ├── fit-rows.js
│ ├── masonry-measure-columns.js
│ ├── get-segment-size.js
│ ├── filtering.js
│ ├── sorting.js
│ ├── arrange-complete.js
│ └── sort-data.js
├── .jshintrc
├── tests.css
└── index.html
├── .github
├── issue_template.md
└── contributing.md
├── .eslintrc.js
├── bower.json
├── sandbox
├── require-js.html
├── browserify
│ ├── jq-main.js
│ ├── main.js
│ └── browserify.html
├── basic.html
├── js
│ └── require-js.js
├── transition-bug.html
├── fluid.html
├── sandbox.css
├── stamps.html
├── insert.html
├── right-to-left.html
├── bottom-up.html
├── fitrows.html
├── sorting.html
├── masonry.html
├── horizontal-layout-modes.html
├── filter-sort.html
├── cells-by-row.html
├── jquery.html
├── combination-filters-inclusive.html
├── combination-filters.html
├── masonry-horizontal.html
└── v3-release-gif2.html
├── js
├── layout-modes
│ ├── vertical.js
│ ├── fit-rows.js
│ └── masonry.js
├── item.js
├── layout-mode.js
└── isotope.js
├── package.json
├── README.md
└── dist
└── isotope.pkgd.min.js
/bin/lint-json.js:
--------------------------------------------------------------------------------
1 | require('../package.json');
2 | require('../bower.json');
3 |
--------------------------------------------------------------------------------
/bin/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [ 'metafizzy' ],
3 | extends: 'plugin:metafizzy/node',
4 | };
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | isotope-site.zip
3 | components/
4 | bower_components/
5 | node_modules/
6 | sandbox/**/bundle.js
7 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "devel": false,
4 | "strict": true,
5 | "undef": true,
6 | "unused": true
7 | }
8 |
--------------------------------------------------------------------------------
/test/unit/helpers.js:
--------------------------------------------------------------------------------
1 | ( function() {
2 |
3 | 'use strict';
4 |
5 | // ----- default layout mode ----- //
6 | Isotope.defaults.layoutMode = 'fitRows';
7 |
8 | } )();
9 |
--------------------------------------------------------------------------------
/test/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "devel": false,
4 | "strict": true,
5 | "undef": true,
6 | "unused": true,
7 | "predef": {
8 | "Isotope": false,
9 | "QUnit": false
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | **Test case:** https://codepen.io/desandro/pen/mEinp
4 |
--------------------------------------------------------------------------------
/bin/version.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const version = require('../package.json').version;
3 |
4 | const file = 'js/isotope.js';
5 | let src = fs.readFileSync( file, 'utf8' );
6 | src = src.replace( /Isotope v\d+\.\d+\.\d+/, `Isotope v${version}` );
7 | fs.writeFileSync( file, src, 'utf8' );
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | module.exports = {
4 | plugins: [ 'metafizzy' ],
5 | extends: 'plugin:metafizzy/browser',
6 | env: {
7 | browser: true,
8 | commonjs: true,
9 | },
10 | parserOptions: {
11 | ecmaVersion: 5,
12 | },
13 | globals: {
14 | Isotope: 'readonly',
15 | QUnit: 'readonly',
16 | define: 'readonly',
17 | },
18 | rules: {
19 | 'no-var': 'off',
20 | 'prefer-spread': 'off',
21 | strict: 'off',
22 | },
23 | ignorePatterns: [
24 | 'sandbox/browserify/bundle.js',
25 | ],
26 | };
27 |
--------------------------------------------------------------------------------
/test/unit/masonry-stamp.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'Masonry stamp', function( assert ) {
2 | 'use strict';
3 |
4 | var iso = new Isotope( '#masonry-stamp', {
5 | layoutMode: 'masonry',
6 | itemSelector: '.item',
7 | stamp: '.stamp',
8 | } );
9 |
10 | function checkPosition( item, x, y ) {
11 | var elem = item.element;
12 | var left = parseInt( elem.style.left, 10 );
13 | var top = parseInt( elem.style.top, 10 );
14 | assert.deepEqual( [ left, top ], [ x, y ], 'item position ' + x + ', ' + y );
15 | }
16 |
17 | checkPosition( iso.items[0], 0, 0 );
18 | checkPosition( iso.items[1], 0, 30 );
19 | checkPosition( iso.items[2], 60, 45 );
20 | checkPosition( iso.items[3], 120, 45 );
21 |
22 | } );
23 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "isotope-layout",
3 | "description": "Filter and sort magical layouts",
4 | "main": "js/isotope.js",
5 | "dependencies": {
6 | "desandro-matches-selector": "^2.0.0",
7 | "fizzy-ui-utils": "^2.0.4",
8 | "get-size": "^2.0.0",
9 | "masonry-layout": "^4.1.0",
10 | "outlayer": "^2.1.0"
11 | },
12 | "devDependencies": {
13 | "jquery": "^3.3.1",
14 | "jquery-bridget": "^2",
15 | "qunit": "^2.6.0"
16 | },
17 | "ignore": [
18 | "test/",
19 | "sandbox/",
20 | "**/.*",
21 | "package.json",
22 | "notes.md",
23 | "node_modules",
24 | "bower_components",
25 | "test",
26 | "tests"
27 | ],
28 | "homepage": "https://isotope.metafizzy.co",
29 | "authors": [
30 | "David DeSandro"
31 | ],
32 | "moduleType": [
33 | "amd",
34 | "globals",
35 | "node"
36 | ],
37 | "keywords": [
38 | "filter",
39 | "sort",
40 | "masonry",
41 | "jquery-plugin"
42 | ],
43 | "license": "GPL-3.0"
44 | }
45 |
--------------------------------------------------------------------------------
/test/unit/fit-rows.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'fitRows', function( assert ) {
2 | 'use strict';
3 |
4 | var iso = new Isotope( '#fitrows-gutter', {
5 | layoutMode: 'fitRows',
6 | itemSelector: '.item',
7 | transitionDuration: 0,
8 | } );
9 |
10 | function checkPosition( item, x, y ) {
11 | var elem = item.element;
12 | var left = parseInt( elem.style.left, 10 );
13 | var top = parseInt( elem.style.top, 10 );
14 | assert.deepEqual( [ left, top ], [ x, y ], 'item position ' + x + ', ' + y );
15 | }
16 |
17 | checkPosition( iso.items[0], 0, 0 );
18 | checkPosition( iso.items[1], 60, 0 );
19 |
20 | // check gutter
21 | iso.options.fitRows = {
22 | gutter: 10,
23 | };
24 | iso.layout();
25 |
26 | checkPosition( iso.items[0], 0, 0 );
27 | checkPosition( iso.items[1], 70, 0 );
28 |
29 | // check gutter, with element sizing
30 | iso.options.fitRows = {
31 | gutter: '.gutter-sizer',
32 | };
33 | iso.layout();
34 |
35 | checkPosition( iso.items[0], 0, 0 );
36 | checkPosition( iso.items[1], 78, 0 );
37 |
38 | } );
39 |
--------------------------------------------------------------------------------
/sandbox/require-js.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | require js
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | require js
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/js/layout-modes/vertical.js:
--------------------------------------------------------------------------------
1 | /**
2 | * vertical layout mode
3 | */
4 |
5 | ( function( window, factory ) {
6 | // universal module definition
7 | if ( typeof define == 'function' && define.amd ) {
8 | // AMD
9 | define( [
10 | '../layout-mode',
11 | ],
12 | factory );
13 | } else if ( typeof module == 'object' && module.exports ) {
14 | // CommonJS
15 | module.exports = factory(
16 | require('../layout-mode')
17 | );
18 | } else {
19 | // browser global
20 | factory(
21 | window.Isotope.LayoutMode
22 | );
23 | }
24 |
25 | }( window, function factory( LayoutMode ) {
26 | 'use strict';
27 |
28 | var Vertical = LayoutMode.create( 'vertical', {
29 | horizontalAlignment: 0,
30 | } );
31 |
32 | var proto = Vertical.prototype;
33 |
34 | proto._resetLayout = function() {
35 | this.y = 0;
36 | };
37 |
38 | proto._getItemLayoutPosition = function( item ) {
39 | item.getSize();
40 | var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
41 | this.options.horizontalAlignment;
42 | var y = this.y;
43 | this.y += item.size.outerHeight;
44 | return { x: x, y: y };
45 | };
46 |
47 | proto._getContainerSize = function() {
48 | return { height: this.y };
49 | };
50 |
51 | return Vertical;
52 |
53 | } ) );
54 |
--------------------------------------------------------------------------------
/test/unit/masonry-measure-columns.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'Masonry.measureColumns', function( assert ) {
2 | 'use strict';
3 |
4 | var iso = new Isotope( '#masonry-measure-columns', {
5 | itemSelector: '.item',
6 | layoutMode: 'masonry',
7 | transitionDuration: 0,
8 | } );
9 |
10 | var msnryMode = iso.modes.masonry;
11 | assert.equal( msnryMode.columnWidth, 60, 'after layout, measured first element' );
12 |
13 | iso.modes.masonry._getMeasurement( 'columnWidth', 'outerWidth' );
14 | assert.equal( msnryMode.columnWidth, 0, '_getMeasurement, no option' );
15 |
16 | iso.modes.masonry.measureColumns();
17 | assert.equal( msnryMode.columnWidth, 60, 'measureColumns, no option' );
18 |
19 | iso.arrange({ filter: '.c' });
20 |
21 | iso.modes.masonry.measureColumns();
22 | assert.equal( msnryMode.columnWidth, 60,
23 | 'measureColumns after filter first item, no option' );
24 |
25 | iso.arrange({
26 | masonry: { columnWidth: 80 },
27 | });
28 | assert.equal( msnryMode.columnWidth, 80,
29 | '.arrange() masonry.columnWidth option set number' );
30 |
31 | iso.arrange({
32 | masonry: { columnWidth: '.grid-sizer' },
33 | });
34 | assert.equal( msnryMode.columnWidth, 70,
35 | '.arrange() masonry.columnWidth option set selector string' );
36 |
37 | } );
38 |
--------------------------------------------------------------------------------
/bin/bundle-js.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const requirejs = require('requirejs');
3 |
4 | // get banner
5 | let isotopeJsSrc = fs.readFileSync( 'js/isotope.js', 'utf8' );
6 | let banner = isotopeJsSrc.split(' */')[0] + ' */\n\n';
7 | banner = banner.replace( 'Isotope', 'Isotope PACKAGED' );
8 |
9 | let options = {
10 | out: 'dist/isotope.pkgd.js',
11 | baseUrl: 'bower_components',
12 | optimize: 'none',
13 | include: [
14 | 'jquery-bridget/jquery-bridget',
15 | 'isotope-layout/js/isotope',
16 | ],
17 | paths: {
18 | 'isotope-layout': '../',
19 | jquery: 'empty:',
20 | },
21 | };
22 |
23 | requirejs.optimize(
24 | options,
25 | function() {
26 | let pkgdSrc = fs.readFileSync( options.out, 'utf8' );
27 | let definitionRE = /define\(\s*'isotope-layout\/js\/isotope'(.|\n)+\],/;
28 | // remove named module
29 | pkgdSrc.replace( definitionRE, function( definition ) {
30 | // remove named module
31 | return definition.replace( "'isotope-layout/js/isotope',", '' )
32 | // use explicit file paths, './item' -> 'isotope-layout/js/item'
33 | .replace( /'.\//g, "'isotope-layout/js/" );
34 | } );
35 | pkgdSrc = banner + pkgdSrc;
36 | fs.writeFileSync( options.out, pkgdSrc );
37 | },
38 | function( err ) {
39 | throw new Error( err );
40 | },
41 | );
42 |
--------------------------------------------------------------------------------
/sandbox/browserify/jq-main.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable id-length */
2 |
3 | var Isotope = window.Isotope = require('../../js/isotope');
4 | var $ = require('jquery');
5 | require('jquery-bridget');
6 |
7 | // enable $().isotope() plugin
8 | $.bridget( 'isotope', Isotope );
9 |
10 | var $container = $('#container').isotope({
11 | layoutMode: 'fitRows',
12 | transitionDuration: '0.8s',
13 | cellsByRow: {
14 | columnWidth: 130,
15 | rowHeight: 140,
16 | },
17 | getSortData: {
18 | number: '.number parseInt',
19 | symbol: '.symbol',
20 | name: '.name',
21 | category: '[data-category]',
22 | weight: function( itemElem ) {
23 | // remove parenthesis
24 | return parseFloat( $( itemElem ).find('.weight')
25 | .text()
26 | .replace( /[()]/g, '' ) );
27 | },
28 | },
29 | });
30 |
31 | $('#options').on( 'click', 'button', function( event ) {
32 | var $target = $( event.target );
33 | var key = $target.parent().attr('data-isotope-key');
34 | var value = $target.attr('data-isotope-value');
35 |
36 | if ( key === 'filter' && value === 'number-greater-than-50' ) {
37 | value = function( elem ) {
38 | var numberText = $( elem ).find('.number')
39 | .text();
40 | return parseInt( numberText, 10 ) > 40;
41 | };
42 | }
43 | console.log( key, value );
44 | var opts = {};
45 | opts[ key ] = value;
46 | $container.isotope( opts );
47 | } );
48 |
--------------------------------------------------------------------------------
/test/unit/get-segment-size.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'LayoutMode.getSegmentSize', function( assert ) {
2 | 'use strict';
3 |
4 | var CellsByRow = Isotope.LayoutMode.create('cellsByRow');
5 |
6 | CellsByRow.prototype._resetLayout = function() {
7 | this.getColumnWidth();
8 | this.getRowHeight();
9 | };
10 |
11 | var iso = new Isotope( '#get-segment-size', {
12 | layoutMode: 'cellsByRow',
13 | itemSelector: '.item',
14 | cellsByRow: {
15 | columnWidth: 17,
16 | rowHeight: 23,
17 | },
18 | } );
19 |
20 | var cellsByRow = iso.modes.cellsByRow;
21 | assert.equal( cellsByRow.columnWidth, 17, 'explicit columnWidth option set' );
22 | assert.equal( cellsByRow.rowHeight, 23, 'explicit rowHeight option set' );
23 |
24 | // set element sizing
25 | iso.options.cellsByRow.columnWidth = '.grid-sizer';
26 | iso.options.cellsByRow.rowHeight = '.grid-sizer';
27 | cellsByRow.getColumnWidth();
28 | cellsByRow.getRowHeight();
29 | assert.equal( cellsByRow.columnWidth, 57, 'element sizing columnWidth' );
30 | assert.equal( cellsByRow.rowHeight, 47, 'element sizing rowHeight' );
31 |
32 | // default to first item
33 | delete iso.options.cellsByRow.columnWidth;
34 | delete iso.options.cellsByRow.rowHeight;
35 | cellsByRow.getColumnWidth();
36 | cellsByRow.getRowHeight();
37 | assert.equal( cellsByRow.columnWidth, 60, 'first item columnWidth' );
38 | assert.equal( cellsByRow.rowHeight, 30, 'first item rowHeight' );
39 |
40 | } );
41 |
--------------------------------------------------------------------------------
/test/tests.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-box-sizing: border-box;
3 | -moz-box-sizing: border-box;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: sans-serif;
9 | }
10 |
11 | .container {
12 | background: #EEE;
13 | width: 180px;
14 | margin-bottom: 20px;
15 | position: relative;
16 | }
17 |
18 | .container:after {
19 | content: '';
20 | display: block;
21 | clear: both;
22 | }
23 |
24 | .item {
25 | width: 60px;
26 | height: 30px;
27 | float: left;
28 | border: 1px solid;
29 | background: #3BF;
30 | }
31 |
32 | .item.w2 { width: 120px; }
33 | .item.w3 { width: 180px; }
34 |
35 | .item.h2 { height: 50px; }
36 | .item.h3 { height: 70px; }
37 | .item.h4 { height: 90px; }
38 | .item.h5 { height: 110px; }
39 |
40 | /* ---- stamp ---- */
41 |
42 |
43 | .stamp {
44 | background: red;
45 | opacity: 0.75;
46 | position: absolute;
47 | border: 1px solid;
48 | }
49 |
50 | .has-stamp {
51 | position: relative;
52 | }
53 |
54 | /* ---- get segment size ---- */
55 |
56 | #get-segment-size .grid-sizer {
57 | /* 57 outer width */
58 | width: 52px;
59 | margin-right: 5px;
60 | /* 47 outer height */
61 | height: 40px;
62 | margin-bottom: 7px;
63 | }
64 |
65 | #masonry-measure-columns .grid-sizer {
66 | width: 70px;
67 | }
68 |
69 | /* ---- masonry stamp ---- */
70 |
71 | #masonry-stamp .stamp1 {
72 | width: 80px;
73 | height: 30px;
74 | right: 25px;
75 | top: 15px;
76 | }
77 |
78 | /* ---- fit rows ---- */
79 |
80 | #fitrows-gutter .gutter-sizer {
81 | width: 10%;
82 | }
83 |
--------------------------------------------------------------------------------
/js/layout-modes/fit-rows.js:
--------------------------------------------------------------------------------
1 | /**
2 | * fitRows layout mode
3 | */
4 |
5 | ( function( window, factory ) {
6 | // universal module definition
7 | if ( typeof define == 'function' && define.amd ) {
8 | // AMD
9 | define( [
10 | '../layout-mode',
11 | ],
12 | factory );
13 | } else if ( typeof exports == 'object' ) {
14 | // CommonJS
15 | module.exports = factory(
16 | require('../layout-mode')
17 | );
18 | } else {
19 | // browser global
20 | factory(
21 | window.Isotope.LayoutMode
22 | );
23 | }
24 |
25 | }( window, function factory( LayoutMode ) {
26 | 'use strict';
27 |
28 | var FitRows = LayoutMode.create('fitRows');
29 |
30 | var proto = FitRows.prototype;
31 |
32 | proto._resetLayout = function() {
33 | this.x = 0;
34 | this.y = 0;
35 | this.maxY = 0;
36 | this._getMeasurement( 'gutter', 'outerWidth' );
37 | };
38 |
39 | proto._getItemLayoutPosition = function( item ) {
40 | item.getSize();
41 |
42 | var itemWidth = item.size.outerWidth + this.gutter;
43 | // if this element cannot fit in the current row
44 | var containerWidth = this.isotope.size.innerWidth + this.gutter;
45 | if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
46 | this.x = 0;
47 | this.y = this.maxY;
48 | }
49 |
50 | var position = {
51 | x: this.x,
52 | y: this.y,
53 | };
54 |
55 | this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
56 | this.x += itemWidth;
57 |
58 | return position;
59 | };
60 |
61 | proto._getContainerSize = function() {
62 | return { height: this.maxY };
63 | };
64 |
65 | return FitRows;
66 |
67 | } ) );
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "isotope-layout",
3 | "version": "3.0.6",
4 | "description": "Filter and sort magical layouts",
5 | "main": "js/isotope.js",
6 | "files": [
7 | "js",
8 | "dist"
9 | ],
10 | "scripts": {
11 | "test": "echo \"Error: no test specified\" && exit 1",
12 | "lint": "node bin/lint-json.js && npx eslint .",
13 | "lintFix": "npx eslint . --fix",
14 | "dist": "npm run bundleJs && npm run uglify",
15 | "bundleJs": "node bin/bundle-js.js",
16 | "uglify": "npx uglifyjs dist/isotope.pkgd.js -o dist/isotope.pkgd.min.js --mangle --comments /^!/",
17 | "version": "node bin/version.js && npm run dist && git add -A css js dist"
18 | },
19 | "dependencies": {
20 | "desandro-matches-selector": "^2.0.0",
21 | "fizzy-ui-utils": "^2.0.4",
22 | "get-size": "^2.0.0",
23 | "masonry-layout": "^4.1.0",
24 | "outlayer": "^2.1.0"
25 | },
26 | "devDependencies": {
27 | "eslint": "^6.8.0",
28 | "eslint-plugin-metafizzy": "^1.0.0",
29 | "jquery": "^3.3.1",
30 | "jquery-bridget": "^2",
31 | "jshint": "^2.11.0",
32 | "qunitjs": "^1.15",
33 | "requirejs": "^2.3.6",
34 | "uglifyjs": "^2.4.11"
35 | },
36 | "repository": {
37 | "type": "git",
38 | "url": "git://github.com/metafizzy/isotope.git"
39 | },
40 | "bugs": {
41 | "url": "https://github.com/metafizzy/isotope/issues"
42 | },
43 | "homepage": "https://isotope.metafizzy.co",
44 | "directories": {
45 | "test": "test"
46 | },
47 | "keywords": [
48 | "DOM",
49 | "browser",
50 | "masonry",
51 | "layout",
52 | "filter",
53 | "sort",
54 | "jquery-plugin"
55 | ],
56 | "author": "Metafizzy",
57 | "license": "GPL-3.0"
58 | }
59 |
--------------------------------------------------------------------------------
/sandbox/browserify/main.js:
--------------------------------------------------------------------------------
1 | var Isotope = window.Isotope = require('../../js/isotope');
2 | var eventie = require('eventie');
3 | var matchesSelector = require('desandro-matches-selector');
4 |
5 | // require('isotope-fit-columns');
6 | // require('isotope-cells-by-column');
7 | // require('isotope-horizontal');
8 | // require('isotope-masonry-horizontal');
9 |
10 | function getText( elem ) {
11 | return elem.textContent || elem.innerText;
12 | }
13 |
14 | var iso = window.iso = new Isotope( '#container', {
15 | layoutMode: 'fitRows',
16 | transitionDuration: '0.8s',
17 | cellsByRow: {
18 | columnWidth: 130,
19 | rowHeight: 140,
20 | },
21 | getSortData: {
22 | number: '.number parseInt',
23 | symbol: '.symbol',
24 | name: '.name',
25 | category: '[data-category]',
26 | weight: function( itemElem ) {
27 | // remove parenthesis
28 | var weight = itemElem.querySelector('.weight').textContent;
29 | return parseFloat( weight.replace( /[()]/g, '' ) );
30 | },
31 | },
32 | } );
33 |
34 | var options = document.querySelector('#options');
35 |
36 | eventie.bind( options, 'click', function( event ) {
37 | if ( !matchesSelector( event.target, 'button' ) ) {
38 | return;
39 | }
40 |
41 | var key = event.target.parentNode.getAttribute('data-isotope-key');
42 | var value = event.target.getAttribute('data-isotope-value');
43 |
44 | if ( key === 'filter' && value === 'number-greater-than-50' ) {
45 | value = function( elem ) {
46 | var numberText = getText( elem.querySelector('.number') );
47 | return parseInt( numberText, 10 ) > 40;
48 | };
49 | }
50 | console.log( key, value );
51 | iso.options[ key ] = value;
52 | iso.arrange();
53 | } );
54 |
--------------------------------------------------------------------------------
/.github/contributing.md:
--------------------------------------------------------------------------------
1 | ## Submitting issues
2 |
3 | ### Reduced test case required
4 |
5 | All bug reports and problem issues require a [**reduced test case**](https://css-tricks.com/reduced-test-cases/). Create one by forking any one of the [CodePen examples](https://codepen.io/desandro/tag/isotope-docs) from [the docs](https://isotope.metafizzy.co).
6 |
7 | **CodePens**
8 |
9 | + [Filtering](https://codepen.io/desandro/pen/Ehgij)
10 | + [Sorting](https://codepen.io/desandro/pen/lzCqe)
11 | + [Filtering and sorting](https://codepen.io/desandro/pen/nFrte)
12 | + [Masonry layout](https://codepen.io/desandro/pen/mEinp)
13 | + [Fluid Masonry layout](https://codepen.io/desandro/pen/mIkhq)
14 |
15 | **Test cases**
16 |
17 | + A reduced test case clearly demonstrates the bug or issue.
18 | + It contains the bare minimum HTML, CSS, and JavaScript required to demonstrate the bug.
19 | + A link to your production site is **not** a reduced test case.
20 |
21 | Providing a reduced test case is the best way to get your issue addressed. Without a reduced test case, your issue may be closed.
22 |
23 | ## Pull requests
24 |
25 | Contributions are welcome!
26 |
27 | Your code may be used as part of a commercial product if merged. Be clear about what license applies to your patch. [The MIT license](https://choosealicense.com/licenses/mit/) or [public domain unlicense](https://choosealicense.com/licenses/unlicense/) are permissive, and allow integration of your patch into Isotope as part of a commercial product.
28 |
29 | Do not edit `dist/` files. I'll update these after your PR has been merged.
30 |
31 | ### Development setup / Sandbox
32 |
33 | After a fresh git clone, to run the examples in sandbox, you will first need to run (from the root directory):
34 |
35 | ```shell
36 | $ npm install bower
37 | $ bower install
38 | ```
39 |
--------------------------------------------------------------------------------
/sandbox/basic.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | basic
7 |
8 |
9 |
10 |
11 |
12 |
13 | basic
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/sandbox/js/require-js.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable id-length */
2 | /* globals requirejs */
3 |
4 | // -------------------------- bower -------------------------- //
5 |
6 | /*
7 | // with bower components
8 | requirejs.config({
9 | baseUrl: '../bower_components'
10 | });
11 |
12 | requirejs( [ '../js/isotope' ], function( Isotope ) {
13 | new Isotope( '#basic', {
14 | masonry: {
15 | columnWidth: 60
16 | }
17 | });
18 | });
19 | // */
20 |
21 | // -------------------------- pkgd -------------------------- //
22 |
23 | /*
24 | requirejs( [ '../dist/isotope.pkgd.js' ], function( Isotope ) {
25 | new Isotope( '#basic', {
26 | layoutMode: 'masonry',
27 | masonry: {
28 | columnWidth: 60
29 | }
30 | });
31 | });
32 | // */
33 |
34 | // -------------------------- bower & jQuery -------------------------- //
35 |
36 | /*
37 | requirejs.config({
38 | baseUrl: '../bower_components',
39 | paths: {
40 | jquery: 'jquery/dist/jquery'
41 | }
42 | })
43 |
44 | requirejs( [
45 | 'jquery',
46 | 'isotope/js/isotope',
47 | 'jquery-bridget/jquery-bridget'
48 | ],
49 | function( $, Isotope ) {
50 | $.bridget( 'isotope', Isotope );
51 | $('#basic').isotope({
52 | masonry: {
53 | columnWidth: 60
54 | }
55 | });
56 | });
57 |
58 | // */
59 |
60 | // -------------------------- pkgd & jQuery -------------------------- //
61 |
62 | // /*
63 | requirejs.config({
64 | paths: {
65 | jquery: '../../bower_components/jquery/dist/jquery',
66 | },
67 | });
68 |
69 | requirejs( [ 'require', 'jquery', '../dist/isotope.pkgd.js' ],
70 | function( require, $, Isotope ) {
71 | require( [
72 | 'jquery-bridget/jquery-bridget',
73 | ],
74 | function() {
75 | $.bridget( 'isotope', Isotope );
76 | $('#basic').isotope({
77 | masonry: {
78 | columnWidth: 60,
79 | },
80 | });
81 | } );
82 | } );
83 |
84 | // */
85 |
86 |
--------------------------------------------------------------------------------
/js/item.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Isotope Item
3 | **/
4 |
5 | ( function( window, factory ) {
6 | // universal module definition
7 | if ( typeof define == 'function' && define.amd ) {
8 | // AMD
9 | define( [
10 | 'outlayer/outlayer',
11 | ],
12 | factory );
13 | } else if ( typeof module == 'object' && module.exports ) {
14 | // CommonJS
15 | module.exports = factory(
16 | require('outlayer')
17 | );
18 | } else {
19 | // browser global
20 | window.Isotope = window.Isotope || {};
21 | window.Isotope.Item = factory(
22 | window.Outlayer
23 | );
24 | }
25 |
26 | }( window, function factory( Outlayer ) {
27 | 'use strict';
28 |
29 | // -------------------------- Item -------------------------- //
30 |
31 | // sub-class Outlayer Item
32 | function Item() {
33 | Outlayer.Item.apply( this, arguments );
34 | }
35 |
36 | var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
37 |
38 | var _create = proto._create;
39 | proto._create = function() {
40 | // assign id, used for original-order sorting
41 | this.id = this.layout.itemGUID++;
42 | _create.call( this );
43 | this.sortData = {};
44 | };
45 |
46 | proto.updateSortData = function() {
47 | if ( this.isIgnored ) {
48 | return;
49 | }
50 | // default sorters
51 | this.sortData.id = this.id;
52 | // for backward compatibility
53 | this.sortData['original-order'] = this.id;
54 | this.sortData.random = Math.random();
55 | // go thru getSortData obj and apply the sorters
56 | var getSortData = this.layout.options.getSortData;
57 | var sorters = this.layout._sorters;
58 | for ( var key in getSortData ) {
59 | var sorter = sorters[ key ];
60 | this.sortData[ key ] = sorter( this.element, this );
61 | }
62 | };
63 |
64 | var _destroy = proto.destroy;
65 | proto.destroy = function() {
66 | // call super
67 | _destroy.apply( this, arguments );
68 | // reset display, #741
69 | this.css({
70 | display: '',
71 | });
72 | };
73 |
74 | return Item;
75 |
76 | } ) );
77 |
--------------------------------------------------------------------------------
/js/layout-modes/masonry.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Masonry layout mode
3 | * sub-classes Masonry
4 | * https://masonry.desandro.com
5 | */
6 |
7 | ( function( window, factory ) {
8 | // universal module definition
9 | if ( typeof define == 'function' && define.amd ) {
10 | // AMD
11 | define( [
12 | '../layout-mode',
13 | 'masonry-layout/masonry',
14 | ],
15 | factory );
16 | } else if ( typeof module == 'object' && module.exports ) {
17 | // CommonJS
18 | module.exports = factory(
19 | require('../layout-mode'),
20 | require('masonry-layout')
21 | );
22 | } else {
23 | // browser global
24 | factory(
25 | window.Isotope.LayoutMode,
26 | window.Masonry
27 | );
28 | }
29 |
30 | }( window, function factory( LayoutMode, Masonry ) {
31 | 'use strict';
32 |
33 | // -------------------------- masonryDefinition -------------------------- //
34 |
35 | // create an Outlayer layout class
36 | var MasonryMode = LayoutMode.create('masonry');
37 |
38 | var proto = MasonryMode.prototype;
39 |
40 | var keepModeMethods = {
41 | _getElementOffset: true,
42 | layout: true,
43 | _getMeasurement: true,
44 | };
45 |
46 | // inherit Masonry prototype
47 | for ( var method in Masonry.prototype ) {
48 | // do not inherit mode methods
49 | if ( !keepModeMethods[ method ] ) {
50 | proto[ method ] = Masonry.prototype[ method ];
51 | }
52 | }
53 |
54 | var measureColumns = proto.measureColumns;
55 | proto.measureColumns = function() {
56 | // set items, used if measuring first item
57 | this.items = this.isotope.filteredItems;
58 | measureColumns.call( this );
59 | };
60 |
61 | // point to mode options for fitWidth
62 | var _getOption = proto._getOption;
63 | proto._getOption = function( option ) {
64 | if ( option == 'fitWidth' ) {
65 | return this.options.isFitWidth !== undefined ?
66 | this.options.isFitWidth : this.options.fitWidth;
67 | }
68 | return _getOption.apply( this.isotope, arguments );
69 | };
70 |
71 | return MasonryMode;
72 |
73 | } ) );
74 |
--------------------------------------------------------------------------------
/sandbox/transition-bug.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | transition bug
7 |
8 |
9 |
12 |
13 |
14 |
15 | transition bug
16 |
17 |
18 |
19 |
20 |
21 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/test/unit/filtering.js:
--------------------------------------------------------------------------------
1 | /* globals jQuery */
2 |
3 | QUnit.test( 'filtering', function( assert ) {
4 | 'use strict';
5 |
6 | var iso = new Isotope( '#filtering', {
7 | isJQueryFiltering: false,
8 | transitionDuration: 0,
9 | } );
10 |
11 | var ids = getFilteredItemIDs( iso );
12 | assert.equal( ids, '1,2,3,4,5,6,7', 'all items there by default' );
13 |
14 | function checkFilter( filter, expectedIDs, message ) {
15 | iso.arrange({ filter: filter });
16 | ids = getFilteredItemIDs( iso );
17 | assert.equal( ids, expectedIDs, message || filter );
18 | }
19 |
20 | checkFilter( '.orange', '1,3,6,7' );
21 | checkFilter( '.tall', '3,4,7' );
22 | checkFilter( '.tall.orange', '3,7' );
23 |
24 | iso.arrange({
25 | filter: function( elem ) {
26 | var num = parseInt( elem.textContent, 10 );
27 | return num > 5;
28 | },
29 | });
30 | ids = getFilteredItemIDs( iso );
31 | assert.equal( ids, '4,5,7', 'function, text is greater than 5' );
32 |
33 | // filter with jQuery
34 | iso.options.isJQueryFiltering = true;
35 |
36 | checkFilter( '.orange', '1,3,6,7', '.orange with jQuery' );
37 | checkFilter( '.tall', '3,4,7', '.orange with jQuery' );
38 | checkFilter( '.tall.orange', '3,7', '.tall.orange with jQuery' );
39 |
40 | checkFilter( ':not(.orange)', '2,4,5' );
41 | checkFilter( '.orange:not(.tall)', '1,6' );
42 |
43 | iso.arrange({
44 | filter: function() {
45 | var num = parseInt( jQuery( this ).text(), 10 );
46 | return num > 5;
47 | },
48 | });
49 | ids = getFilteredItemIDs( iso );
50 | assert.equal( ids, '4,5,7', 'function, text is greater than 5, with jQuery' );
51 |
52 | // ----- helper ----- //
53 |
54 | /*
55 | 5
56 | 3
57 | 2
58 | 9
59 | 7
60 | 1
61 | 8
62 | */
63 |
64 | // return a string of item ids
65 | function getFilteredItemIDs( isotope ) {
66 | return isotope.filteredItems.map( function( item ) {
67 | return item.element.getAttribute('data-item-id');
68 | } );
69 | }
70 |
71 | } );
72 |
--------------------------------------------------------------------------------
/test/unit/sorting.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'sorting', function( assert ) {
2 |
3 | 'use strict';
4 |
5 | // sorting with history
6 | ( function() {
7 | var iso = new Isotope( '#sorting1', {
8 | layoutMode: 'fitRows',
9 | transitionDuration: 0,
10 | getSortData: {
11 | letter: 'b',
12 | number: 'i',
13 | },
14 | sortBy: 'number',
15 | } );
16 |
17 | iso.arrange({ sortBy: 'letter' });
18 |
19 | var texts = getItemsText( iso );
20 |
21 | assert.equal( texts, 'A1,A2,A3,A4,B1,B2,B4',
22 | 'items sorted by letter, then number, via history' );
23 |
24 | iso.destroy();
25 | } )();
26 |
27 | // sorting with array
28 | ( function() {
29 | var iso = new Isotope( '#sorting1', {
30 | layoutMode: 'fitRows',
31 | transitionDuration: 0,
32 | getSortData: {
33 | letter: 'b',
34 | number: 'i',
35 | },
36 | sortBy: [ 'letter', 'number' ],
37 | } );
38 |
39 | assert.equal( getItemsText( iso ), 'A1,A2,A3,A4,B1,B2,B4', 'sortBy array' );
40 |
41 | iso.arrange({
42 | sortAscending: false,
43 | });
44 | assert.equal( getItemsText( iso ), 'B4,B2,B1,A4,A3,A2,A1', 'sortAscending false' );
45 |
46 | iso.arrange({
47 | sortAscending: {
48 | letter: true,
49 | number: false,
50 | },
51 | });
52 | assert.equal( getItemsText( iso ),
53 | 'A4,A3,A2,A1,B4,B2,B1', 'sortAscending with object' );
54 |
55 | iso.destroy();
56 | } )();
57 |
58 | ( function() {
59 | var iso = new Isotope( '#sorting2', {
60 | layoutMode: 'fitRows',
61 | transitionDuration: 0,
62 | getSortData: {
63 | letter: 'b',
64 | number: 'i',
65 | axis: 'span',
66 | },
67 | sortBy: [ 'axis' ],
68 | } );
69 |
70 | iso.arrange({ sortBy: 'number' });
71 | assert.equal( getItemsText( iso ), 'B1X,A1X,B1Y,A1Y,B2X,A2X,B2Y,A2Y',
72 | 'sort history 1' );
73 |
74 | iso.arrange({ sortBy: 'letter' });
75 | assert.equal( getItemsText( iso ), 'A1X,A1Y,A2X,A2Y,B1X,B1Y,B2X,B2Y',
76 | 'sort history 2' );
77 |
78 | } )();
79 |
80 | function getItemsText( iso ) {
81 | var texts = iso.filteredItems.map( function( item ) {
82 | return item.element.textContent;
83 | } );
84 | return texts.join(',');
85 | }
86 |
87 | } );
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Isotope
2 |
3 | _Filter & sort magical layouts_
4 |
5 | See [isotope.metafizzy.co](https://isotope.metafizzy.co) for complete docs and demos.
6 |
7 | ## Install
8 |
9 | ### Download
10 |
11 | + [isotope.pkgd.js](https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.js) un-minified, or
12 | + [isotope.pkgd.min.js](https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js) minified
13 |
14 | ### CDN
15 |
16 | Link directly to Isotope files on [unpkg](https://unpkg.com).
17 |
18 | ``` html
19 |
20 |
21 |
22 | ```
23 |
24 | ### Package managers
25 |
26 | npm: `npm install isotope-layout --save`
27 |
28 | Bower: `bower install isotope-layout --save`
29 |
30 | ## License
31 |
32 | ### Commercial license
33 |
34 | If you want to use Isotope to develop commercial sites, themes, projects, and applications, the Commercial license is the appropriate license. With this option, your source code is kept proprietary. Purchase an Isotope Commercial License at [isotope.metafizzy.co](https://isotope.metafizzy.co/#commercial-license)
35 |
36 | ### Open source license
37 |
38 | If you are creating an open source application under a license compatible with the [GNU GPL license v3](https://www.gnu.org/licenses/gpl-3.0.html), you may use Isotope under the terms of the GPLv3.
39 |
40 | [Read more about Isotope's license](https://isotope.metafizzy.co/license.html).
41 |
42 | ## Initialize
43 |
44 | With jQuery
45 |
46 | ``` js
47 | $('.grid').isotope({
48 | // options...
49 | itemSelector: '.grid-item',
50 | masonry: {
51 | columnWidth: 200
52 | }
53 | });
54 | ```
55 |
56 | With vanilla JavaScript
57 |
58 | ``` js
59 | // vanilla JS
60 | var grid = document.querySelector('.grid');
61 | var iso = new Isotope( grid, {
62 | // options...
63 | itemSelector: '.grid-item',
64 | masonry: {
65 | columnWidth: 200
66 | }
67 | });
68 | ```
69 |
70 | With HTML
71 |
72 | Add a `data-isotope` attribute to your element. Options can be set in JSON in the value.
73 |
74 | ``` html
75 |
81 | ```
82 |
83 | * * *
84 |
85 | By [Metafizzy 🌈🐻](https://metafizzy.co), 2010–2020
86 |
--------------------------------------------------------------------------------
/sandbox/fluid.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | fluid
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 | fluid
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/sandbox/sandbox.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | #container,
6 | .container {
7 | background: #EEE;
8 | width: 50%;
9 | margin-bottom: 20px;
10 | }
11 |
12 | .item {
13 | width: 60px;
14 | height: 60px;
15 | float: left;
16 | border: 1px solid;
17 | background: #09F;
18 | }
19 |
20 | .item.w2 { width: 120px; }
21 | .item.w3 { width: 180px; }
22 |
23 | .item.h2 { height: 100px; }
24 | .item.h3 { height: 160px; }
25 | .item.h4 { height: 220px; }
26 | .item.h5 { height: 280px; }
27 |
28 | .stamp {
29 | background: red;
30 | opacity: 0.75;
31 | position: absolute;
32 | border: 1px solid;
33 | }
34 |
35 |
36 | /* element */
37 |
38 | .element {
39 | width: 80px;
40 | height: 90px;
41 | margin: 5px;
42 | background: #DDD;
43 | float: left;
44 | position: relative;
45 | padding: 5px;
46 | }
47 |
48 | .element > * {
49 | margin: 0;
50 | }
51 |
52 | .element .number {
53 | right: 5px;
54 | top: 5px;
55 | position: absolute;
56 | }
57 |
58 | .element .symbol {
59 | font-size: 30px;
60 | left: 5px;
61 | top: 5px;
62 | color: white;
63 | }
64 |
65 | .element .name {
66 | font-size: 14px;
67 | }
68 |
69 | .element .weight {
70 | font-size: 14px;
71 | }
72 |
73 | .element.alkali { background: #F00; background: hsl( 0, 100%, 50%); }
74 | .element.alkaline-earth { background: #F80; background: hsl( 36, 100%, 50%); }
75 | .element.lanthanoid { background: #FF0; background: hsl( 72, 100%, 50%); }
76 | .element.actinoid { background: #0F0; background: hsl( 108, 100%, 50%); }
77 | .element.transition { background: #0F8; background: hsl( 144, 100%, 50%); }
78 | .element.post-transition { background: #0FF; background: hsl( 180, 100%, 50%); }
79 | .element.metalloid { background: #08F; background: hsl( 216, 100%, 50%); }
80 | .element.other.nonmetal { background: #00F; background: hsl( 252, 100%, 50%); }
81 | .element.halogen { background: #F0F; background: hsl( 288, 100%, 50%); }
82 | .element.noble-gas { background: #F08; background: hsl( 324, 100%, 50%); }
83 |
84 | /* stamps */
85 |
86 | .stamp {
87 | position: absolute;
88 | background: hsla(0, 100%, 50%, 0.8);
89 | border: 1px solid;
90 | }
91 |
92 | .stamp1 {
93 | left: 10%;
94 | top: 20px;
95 | width: 20%;
96 | height: 200px;
97 | }
98 |
99 | .stamp2 {
100 | right: 200px;
101 | top: 100px;
102 | width: 100px;
103 | height: 100px;
104 | }
105 |
--------------------------------------------------------------------------------
/sandbox/stamps.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stamps
7 |
8 |
9 |
10 |
11 |
48 |
49 |
50 |
51 |
52 | stamps
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/sandbox/insert.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | insert
8 |
9 |
10 |
11 |
12 |
13 |
14 | insert
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
49
24 |
35
25 |
60
26 |
29
27 |
78
28 |
92
29 |
10
30 |
55
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/test/unit/arrange-complete.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'arrangeComplete', function( assert ) {
2 | 'use strict';
3 |
4 | var iso = new Isotope( '#arrange-complete', {
5 | layoutMode: 'fitRows',
6 | transitionDuration: '0.1s',
7 | } );
8 |
9 | var done = assert.async();
10 |
11 | var tests = [
12 | function() {
13 | iso.once( 'arrangeComplete', function() {
14 | assert.ok( true, 'arrangeComplete after some were filtered' );
15 | next();
16 | } );
17 |
18 | iso.arrange({
19 | filter: '.a1',
20 | });
21 | },
22 | function() {
23 | iso.once( 'arrangeComplete', function() {
24 | assert.ok( true, 'after some revealed, some hidden, some same' );
25 | next();
26 | } );
27 |
28 | iso.arrange({
29 | filter: '.b2',
30 | });
31 | },
32 | function() {
33 | iso.once( 'arrangeComplete', function() {
34 | assert.ok( true, 'after random sort' );
35 | next();
36 | } );
37 |
38 | iso.arrange({
39 | sortBy: 'random',
40 | });
41 | },
42 | function() {
43 | var ticks = 0;
44 | function onArrangeComplete() {
45 | ticks++;
46 | if ( ticks == 2 ) {
47 | assert.ok( true, 'after layout mid-way thru transition' );
48 | iso.off( 'arrangeComplete', onArrangeComplete );
49 | return next();
50 | } else if ( ticks > 2 ) {
51 | assert.ok( false, 'more ticks happened' );
52 | }
53 | }
54 |
55 | iso.on( 'arrangeComplete', onArrangeComplete );
56 |
57 | iso.arrange({
58 | filter: '.a2',
59 | transitionDuration: '0.6s',
60 | });
61 |
62 | setTimeout( function() {
63 | iso.arrange({
64 | filter: '.b2',
65 | });
66 | }, 300 );
67 | },
68 | // stagger
69 | function() {
70 | iso.once( 'arrangeComplete', function() {
71 | assert.ok( true, 'arrangeComplete with stagger' );
72 | next();
73 | } );
74 |
75 | iso.arrange({
76 | stagger: 100,
77 | sortBy: 'random',
78 | filter: '*',
79 | transitionDuration: '0.4s',
80 | });
81 | },
82 | // stagger, triggered mid-transition
83 | function() {
84 | var ticks = 0;
85 | function onArrangeComplete() {
86 | ticks++;
87 | if ( ticks == 2 ) {
88 | assert.ok( true, 'after layout mid-way thru transition, with stagger' );
89 | iso.off( 'arrangeComplete', onArrangeComplete );
90 | iso.options.stagger = 0;
91 | return next();
92 | } else if ( ticks > 2 ) {
93 | assert.ok( false, 'more ticks happened' );
94 | }
95 | }
96 |
97 | iso.on( 'arrangeComplete', onArrangeComplete );
98 |
99 | iso.arrange({
100 | stagger: 100,
101 | sortBy: 'random',
102 | transitionDuration: '0.4s',
103 | });
104 |
105 | setTimeout( function() {
106 | iso.arrange({
107 | filter: '.a1',
108 | });
109 | }, 250 );
110 | },
111 | ];
112 |
113 | function next() {
114 | if ( tests.length ) {
115 | var nextTest = tests.shift();
116 | // HACK for consecutive arrangeComplete calls
117 | setTimeout( nextTest );
118 | } else {
119 | done();
120 | }
121 | }
122 |
123 | next();
124 |
125 | } );
126 |
--------------------------------------------------------------------------------
/sandbox/right-to-left.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | right to left
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 | right to left
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/sandbox/bottom-up.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | bottom up
7 |
8 |
9 |
10 |
25 |
26 |
27 |
28 |
29 | bottom up
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/sandbox/fitrows.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | fitRows
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 | fitRows
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/test/unit/sort-data.js:
--------------------------------------------------------------------------------
1 | /* globals jQuery */
2 |
3 | QUnit.test( 'sort data', function( assert ) {
4 |
5 | 'use strict';
6 |
7 | var iso = new Isotope( '#get-sort-data', {
8 | layoutMode: 'fitRows',
9 | getSortData: {
10 | ninjaTurtle: '[data-ninja-turtle]',
11 | fruit: 'span.fruit',
12 | b: 'b parseFloat',
13 | i: 'i parseInt',
14 | bbroke: 'b foobar',
15 | },
16 | } );
17 |
18 | var item0 = iso.items[0];
19 | var item1 = iso.items[1];
20 |
21 | assert.equal( item0.sortData.ninjaTurtle, 'leonardo', '[data-attr] shorthand' );
22 | assert.equal( item0.sortData.fruit, 'watermelon', 'query selector shorthand' );
23 | assert.equal( item0.sortData.b, 3.14, 'parseFloat parser' );
24 | assert.equal( item0.sortData.i, 42, 'parseInt parser' );
25 | assert.equal( item0.sortData.bbroke, '3.14', 'default nonparser' );
26 |
27 | // ----- ----- //
28 |
29 | var docElem = document.documentElement;
30 | var textSetter = docElem.textContent !== undefined ? 'textContent' : 'innerText';
31 |
32 | function setText( elem, value ) {
33 | elem[ textSetter ] = value;
34 | }
35 |
36 | var elem0 = iso.items[0].element;
37 | var elem1 = iso.items[1].element;
38 |
39 | elem0.setAttribute( 'data-ninja-turtle', 'donatello' );
40 | setText( elem0.querySelector('span.fruit'), 'mango' );
41 | setText( elem0.querySelector('b'), '7.24' );
42 | setText( elem0.querySelector('i'), 'foo' );
43 |
44 | iso.updateSortData( elem0 );
45 |
46 | var message = ', after updateSortData on single item';
47 | assert.equal( item0.sortData.ninjaTurtle, 'donatello',
48 | '[data-attr] shorthand' + message );
49 | assert.equal( item0.sortData.fruit, 'mango',
50 | 'query selector shorthand' + message );
51 | assert.equal( item0.sortData.b, 7.24, 'parseFloat parser' + message );
52 | assert.ok( isNaN( item0.sortData.i ), 'parseInt parser' + message );
53 | assert.equal( item0.sortData.bbroke, '7.24', 'default nonparser' + message );
54 |
55 | // ----- update all items ----- //
56 |
57 | elem0.setAttribute( 'data-ninja-turtle', 'leonardo' );
58 | setText( elem0.querySelector('span.fruit'), 'passion fruit' );
59 |
60 | elem1.setAttribute( 'data-ninja-turtle', 'michelangelo' );
61 | setText( elem1.querySelector('span.fruit'), 'starfruit' );
62 |
63 | // update all
64 | iso.updateSortData();
65 |
66 | message = ', after updateSortData on all items';
67 | assert.equal( item0.sortData.ninjaTurtle, 'leonardo',
68 | '[data-attr] shorthand' + message );
69 | assert.equal( item0.sortData.fruit, 'passion fruit',
70 | 'query selector shorthand' + message );
71 | assert.equal( item1.sortData.ninjaTurtle, 'michelangelo',
72 | '[data-attr] shorthand' + message );
73 | assert.equal( item1.sortData.fruit, 'starfruit',
74 | 'query selector shorthand' + message );
75 |
76 | // ----- no items ----- //
77 |
78 | iso.options.itemSelector = 'none';
79 | iso.reloadItems();
80 |
81 | iso.updateSortData();
82 | assert.ok( true, 'updateSortData on empty container is ok' );
83 |
84 | iso.updateSortData( document.createElement('div') );
85 | assert.ok( true, 'updateSortData with non-item is ok, with no child items' );
86 |
87 | iso.updateSortData( false );
88 | assert.ok( true, 'updateSortData with falsy is ok, with no child items' );
89 |
90 | iso.updateSortData([]);
91 | assert.ok( true, 'updateSortData with empty array is ok, with no child items' );
92 |
93 | iso.updateSortData( jQuery() );
94 | assert.ok( true, 'updateSortData with empty jQuery object is ok, with no child items' );
95 |
96 | // ----- bad getSortData ----- //
97 |
98 | delete iso.options.itemSelector;
99 | iso.options.getSortData.badQuery = 'bad-query';
100 | iso.options.getSortData.badAttr = '[bad-attr]';
101 | iso._getSorters();
102 | iso.reloadItems();
103 |
104 | item0 = iso.items[0];
105 |
106 | assert.equal( item0.sortData.badQuery, null, 'bad query returns null' );
107 | assert.equal( item0.sortData.badAttr, null, 'bad attr returns null' );
108 |
109 | } );
110 |
--------------------------------------------------------------------------------
/js/layout-mode.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Isotope LayoutMode
3 | */
4 |
5 | ( function( window, factory ) {
6 | // universal module definition
7 | if ( typeof define == 'function' && define.amd ) {
8 | // AMD
9 | define( [
10 | 'get-size/get-size',
11 | 'outlayer/outlayer',
12 | ],
13 | factory );
14 | } else if ( typeof module == 'object' && module.exports ) {
15 | // CommonJS
16 | module.exports = factory(
17 | require('get-size'),
18 | require('outlayer')
19 | );
20 | } else {
21 | // browser global
22 | window.Isotope = window.Isotope || {};
23 | window.Isotope.LayoutMode = factory(
24 | window.getSize,
25 | window.Outlayer
26 | );
27 | }
28 |
29 | }( window, function factory( getSize, Outlayer ) {
30 | 'use strict';
31 |
32 | // layout mode class
33 | function LayoutMode( isotope ) {
34 | this.isotope = isotope;
35 | // link properties
36 | if ( isotope ) {
37 | this.options = isotope.options[ this.namespace ];
38 | this.element = isotope.element;
39 | this.items = isotope.filteredItems;
40 | this.size = isotope.size;
41 | }
42 | }
43 |
44 | var proto = LayoutMode.prototype;
45 |
46 | /**
47 | * some methods should just defer to default Outlayer method
48 | * and reference the Isotope instance as `this`
49 | **/
50 | var facadeMethods = [
51 | '_resetLayout',
52 | '_getItemLayoutPosition',
53 | '_manageStamp',
54 | '_getContainerSize',
55 | '_getElementOffset',
56 | 'needsResizeLayout',
57 | '_getOption',
58 | ];
59 |
60 | facadeMethods.forEach( function( methodName ) {
61 | proto[ methodName ] = function() {
62 | return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
63 | };
64 | } );
65 |
66 | // ----- ----- //
67 |
68 | // for horizontal layout modes, check vertical size
69 | proto.needsVerticalResizeLayout = function() {
70 | // don't trigger if size did not change
71 | var size = getSize( this.isotope.element );
72 | // check that this.size and size are there
73 | // IE8 triggers resize on body size change, so they might not be
74 | var hasSizes = this.isotope.size && size;
75 | return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
76 | };
77 |
78 | // ----- measurements ----- //
79 |
80 | proto._getMeasurement = function() {
81 | this.isotope._getMeasurement.apply( this, arguments );
82 | };
83 |
84 | proto.getColumnWidth = function() {
85 | this.getSegmentSize( 'column', 'Width' );
86 | };
87 |
88 | proto.getRowHeight = function() {
89 | this.getSegmentSize( 'row', 'Height' );
90 | };
91 |
92 | /**
93 | * get columnWidth or rowHeight
94 | * @param {String} segment - 'column' or 'row'
95 | * @param {String} size - 'Width' or 'Height'
96 | */
97 | proto.getSegmentSize = function( segment, size ) {
98 | var segmentName = segment + size;
99 | var outerSize = 'outer' + size;
100 | // columnWidth / outerWidth // rowHeight / outerHeight
101 | this._getMeasurement( segmentName, outerSize );
102 | // got rowHeight or columnWidth, we can chill
103 | if ( this[ segmentName ] ) {
104 | return;
105 | }
106 | // fall back to item of first element
107 | var firstItemSize = this.getFirstItemSize();
108 | this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
109 | // or size of container
110 | this.isotope.size[ 'inner' + size ];
111 | };
112 |
113 | proto.getFirstItemSize = function() {
114 | var firstItem = this.isotope.filteredItems[0];
115 | return firstItem && firstItem.element && getSize( firstItem.element );
116 | };
117 |
118 | // ----- methods that should reference isotope ----- //
119 |
120 | proto.layout = function() {
121 | this.isotope.layout.apply( this.isotope, arguments );
122 | };
123 |
124 | proto.getSize = function() {
125 | this.isotope.getSize();
126 | this.size = this.isotope.size;
127 | };
128 |
129 | // -------------------------- create -------------------------- //
130 |
131 | LayoutMode.modes = {};
132 |
133 | LayoutMode.create = function( namespace, options ) {
134 |
135 | function Mode() {
136 | LayoutMode.apply( this, arguments );
137 | }
138 |
139 | Mode.prototype = Object.create( proto );
140 | Mode.prototype.constructor = Mode;
141 |
142 | // default options
143 | if ( options ) {
144 | Mode.options = options;
145 | }
146 |
147 | Mode.prototype.namespace = namespace;
148 | // register in Isotope
149 | LayoutMode.modes[ namespace ] = Mode;
150 |
151 | return Mode;
152 | };
153 |
154 | return LayoutMode;
155 |
156 | } ) );
157 |
--------------------------------------------------------------------------------
/sandbox/browserify/browserify.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Browserify
7 |
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 | Browserify
21 |
22 |
23 |
Filter
24 |
25 |
26 |
27 |
28 |
29 |
30 |
Sort
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
56 |
57 |
58 |
83
59 |
Bi
60 |
Bismuth
61 |
208.9804
62 |
63 |
64 |
70 |
71 |
77 |
78 |
84 |
85 |
86 |
81
87 |
Tl
88 |
Thallium
89 |
204.3833
90 |
91 |
92 |
98 |
99 |
105 |
106 |
112 |
113 |
119 |
120 |
126 |
127 |
133 |
134 |
140 |
141 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Isotope tests
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Isotope tests
44 |
45 |
46 |
47 | Sorting
48 |
49 |
50 |
B4
51 |
B2
52 |
A4
53 |
A1
54 |
B1
55 |
A3
56 |
A2
57 |
58 |
59 |
60 |
B2Y
61 |
B1Y
62 |
B2X
63 |
B1X
64 |
A2Y
65 |
A1Y
66 |
A2X
67 |
A1X
68 |
69 |
70 | getSortData
71 |
72 |
73 |
74 | watermelon
75 | 3.14
76 | 42
77 |
78 |
79 | papaya
80 | 2.13
81 | 1001
82 |
83 |
84 |
85 | Filtering
86 |
87 |
88 |
5
89 |
3
90 |
2
91 |
9
92 |
7
93 |
1
94 |
8
95 |
96 |
97 | layoutComplete
98 |
99 |
100 |
a1 b1
101 |
a2 b1
102 |
a3 b1
103 |
a1 b2
104 |
a2 b2
105 |
a3 b2
106 |
a1 b3
107 |
a2 b3
108 |
a3 b3
109 |
110 |
111 | LayoutMode.getSegmentSize
112 |
113 |
117 |
118 | Masonry
119 |
120 |
121 |
122 |
a
123 |
b
124 |
c
125 |
126 |
127 | Masonry stamp
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | fitRows
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/sandbox/sorting.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | sorting
7 |
8 |
9 |
10 |
11 |
12 |
13 | sorting
14 |
15 |
26 |
27 |
28 |
29 |
35 |
36 |
42 |
43 |
44 |
83
45 |
Bi
46 |
Bismuth
47 |
208.9804
48 |
49 |
50 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
81
73 |
Tl
74 |
Thallium
75 |
204.3833
76 |
77 |
78 |
84 |
85 |
91 |
92 |
98 |
99 |
105 |
106 |
112 |
113 |
119 |
120 |
126 |
127 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/sandbox/masonry.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | masonry
7 |
8 |
9 |
21 |
22 |
23 |
24 |
25 | sorting
26 |
27 |
28 |
Sort
29 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
48 |
49 |
55 |
56 |
57 |
83
58 |
Bi
59 |
Bismuth
60 |
208.9804
61 |
62 |
63 |
69 |
70 |
76 |
77 |
83 |
84 |
85 |
81
86 |
Tl
87 |
Thallium
88 |
204.3833
89 |
90 |
91 |
97 |
98 |
104 |
105 |
111 |
112 |
118 |
119 |
125 |
126 |
132 |
133 |
139 |
140 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
200 |
201 |
202 |
203 |
--------------------------------------------------------------------------------
/sandbox/horizontal-layout-modes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | horizontal layout modes
7 |
8 |
9 |
19 |
20 |
21 |
22 | horizontal layout modes
23 |
24 |
25 |
Filter
26 |
27 | show all
28 | metal
29 | post-transition
30 |
31 |
Sort
32 |
33 | original-order
34 | number
35 | name
36 | symbol
37 | weight
38 | category
39 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
83
60 |
Bi
61 |
Bismuth
62 |
208.9804
63 |
64 |
65 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
81
88 |
Tl
89 |
Thallium
90 |
204.3833
91 |
92 |
93 |
99 |
100 |
106 |
107 |
113 |
114 |
120 |
121 |
127 |
128 |
134 |
135 |
141 |
142 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/sandbox/filter-sort.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | filter sort
7 |
8 |
9 |
12 |
13 |
14 |
15 | filter sort
16 |
17 |
18 |
Filter
19 |
20 | show all
21 | metal
22 | post-transition
23 | number > 50
24 |
25 |
Sort
26 |
27 | original-order
28 | number
29 | name
30 | symbol
31 | weight
32 | category
33 |
34 |
35 |
36 |
37 |
38 |
44 |
45 |
51 |
52 |
53 |
83
54 |
Bi
55 |
Bismuth
56 |
208.9804
57 |
58 |
59 |
65 |
66 |
72 |
73 |
79 |
80 |
81 |
81
82 |
Tl
83 |
Thallium
84 |
204.3833
85 |
86 |
87 |
93 |
94 |
100 |
101 |
107 |
108 |
114 |
115 |
121 |
122 |
128 |
129 |
135 |
136 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/sandbox/cells-by-row.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | cellsByRow
7 |
8 |
9 |
21 |
22 |
23 |
24 |
25 | cellsByRow
26 |
27 |
38 |
39 |
40 |
41 |
47 |
48 |
54 |
55 |
56 |
83
57 |
Bi
58 |
Bismuth
59 |
208.9804
60 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
84 |
81
85 |
Tl
86 |
Thallium
87 |
204.3833
88 |
89 |
90 |
96 |
97 |
103 |
104 |
110 |
111 |
117 |
118 |
124 |
125 |
131 |
132 |
138 |
139 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
216 |
217 |
218 |
219 |
--------------------------------------------------------------------------------
/sandbox/jquery.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | jquery
8 |
9 |
10 |
13 |
14 |
15 |
16 | jquery
17 |
18 |
19 |
Filter
20 |
21 | show all
22 | metal
23 | post-transition
24 | number > 50
25 |
26 |
Sort
27 |
28 | original-order
29 | number
30 | name
31 | symbol
32 | weight
33 | category
34 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
52 |
53 |
54 |
83
55 |
Bi
56 |
Bismuth
57 |
208.9804
58 |
59 |
60 |
66 |
67 |
73 |
74 |
80 |
81 |
82 |
81
83 |
Tl
84 |
Thallium
85 |
204.3833
86 |
87 |
88 |
94 |
95 |
101 |
102 |
108 |
109 |
115 |
116 |
122 |
123 |
129 |
130 |
136 |
137 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
215 |
216 |
217 |
218 |
--------------------------------------------------------------------------------
/sandbox/combination-filters-inclusive.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | combination filters inclusive
7 |
8 |
9 |
131 |
132 |
133 |
134 |
135 | combination filters
136 |
137 |
138 |
139 |
140 |
Color
141 |
142 | any
143 | red
144 | blue
145 | yellow
146 |
147 |
148 |
149 |
150 |
Size
151 |
152 | any
153 | small
154 | wide
155 | big
156 | tall
157 |
158 |
159 |
160 |
161 |
Shape
162 |
163 | any
164 | round
165 | square
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
254 |
255 |
256 |
257 |
--------------------------------------------------------------------------------
/sandbox/combination-filters.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | combination filters
7 |
8 |
9 |
131 |
132 |
133 |
134 |
135 | combination filters
136 |
137 |
138 |
139 |
140 |
Color
141 |
142 | any
143 | red
144 | blue
145 | yellow
146 |
147 |
148 |
149 |
150 |
Size
151 |
152 | any
153 | small
154 | wide
155 | big
156 | tall
157 |
158 |
159 |
160 |
161 |
Shape
162 |
163 | any
164 | round
165 | square
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
255 |
256 |
257 |
258 |
--------------------------------------------------------------------------------
/sandbox/masonry-horizontal.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | horizontal layout modes
7 |
8 |
9 |
45 |
46 |
47 |
48 | horizontal layout modes
49 |
50 |
51 |
Filter
52 |
53 | show all
54 | metal
55 | post-transition
56 |
57 |
Sort
58 |
59 | original-order
60 | number
61 | name
62 | symbol
63 | weight
64 | category
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
83
89 |
Bi
90 |
Bismuth
91 |
208.9804
92 |
93 |
94 |
100 |
101 |
107 |
108 |
114 |
115 |
116 |
81
117 |
Tl
118 |
Thallium
119 |
204.3833
120 |
121 |
122 |
128 |
129 |
135 |
136 |
142 |
143 |
149 |
150 |
156 |
157 |
163 |
164 |
170 |
171 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
245 |
246 |
247 |
248 |
--------------------------------------------------------------------------------
/sandbox/v3-release-gif2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | v3 release gif
8 |
9 |
142 |
143 |
144 |
145 |
146 | v3 release gif
147 |
148 |
149 | Original
150 | Red
151 | Red & Gold
152 | Blue
153 | 123
154 |
155 |
156 |
157 |
158 | A
159 | 8
160 |
161 |
162 | B
163 | 12
164 |
165 |
166 | C
167 | 15
168 |
169 |
170 | D
171 | 10
172 |
173 |
174 | E
175 | 9
176 |
177 |
178 | F
179 | 3
180 |
181 |
182 | G
183 | 4
184 |
185 |
186 | H
187 | 12
188 |
189 |
190 | I
191 | 16
192 |
193 |
194 | J
195 | 1
196 |
197 |
198 | K
199 | 11
200 |
201 |
202 | L
203 | 7
204 |
205 |
206 | M
207 | 19
208 |
209 |
210 | N
211 | 13
212 |
213 |
214 | O
215 | 17
216 |
217 |
218 | P
219 | 14
220 |
221 |
222 | Q
223 | 20
224 |
225 |
226 | R
227 | 6
228 |
229 |
230 | S
231 | 2
232 |
233 |
234 | T
235 | 5
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
273 |
274 |
275 |
276 |
--------------------------------------------------------------------------------
/js/isotope.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Isotope v3.0.6
3 | *
4 | * Licensed GPLv3 for open source use
5 | * or Isotope Commercial License for commercial use
6 | *
7 | * https://isotope.metafizzy.co
8 | * Copyright 2010-2020 Metafizzy
9 | */
10 |
11 | /* eslint-disable max-params */
12 |
13 | ( function( window, factory ) {
14 | // universal module definition
15 | if ( typeof define == 'function' && define.amd ) {
16 | // AMD
17 | define( [
18 | 'outlayer/outlayer',
19 | 'get-size/get-size',
20 | 'desandro-matches-selector/matches-selector',
21 | 'fizzy-ui-utils/utils',
22 | './item',
23 | './layout-mode',
24 | // include default layout modes
25 | './layout-modes/masonry',
26 | './layout-modes/fit-rows',
27 | './layout-modes/vertical',
28 | ],
29 | function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
30 | return factory( window, Outlayer, getSize, matchesSelector, utils,
31 | Item, LayoutMode );
32 | } );
33 | } else if ( typeof module == 'object' && module.exports ) {
34 | // CommonJS
35 | module.exports = factory(
36 | window,
37 | require('outlayer'),
38 | require('get-size'),
39 | require('desandro-matches-selector'),
40 | require('fizzy-ui-utils'),
41 | require('./item'),
42 | require('./layout-mode'),
43 | // include default layout modes
44 | require('./layout-modes/masonry'),
45 | require('./layout-modes/fit-rows'),
46 | require('./layout-modes/vertical')
47 | );
48 | } else {
49 | // browser global
50 | window.Isotope = factory(
51 | window,
52 | window.Outlayer,
53 | window.getSize,
54 | window.matchesSelector,
55 | window.fizzyUIUtils,
56 | window.Isotope.Item,
57 | window.Isotope.LayoutMode
58 | );
59 | }
60 |
61 | }( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
62 | Item, LayoutMode ) {
63 |
64 | 'use strict';
65 |
66 | // -------------------------- vars -------------------------- //
67 |
68 | var jQuery = window.jQuery;
69 |
70 | // -------------------------- helpers -------------------------- //
71 |
72 | var trim = String.prototype.trim ?
73 | function( str ) {
74 | return str.trim();
75 | } :
76 | function( str ) {
77 | return str.replace( /^\s+|\s+$/g, '' );
78 | };
79 |
80 | // -------------------------- isotopeDefinition -------------------------- //
81 |
82 | // create an Outlayer layout class
83 | var Isotope = Outlayer.create( 'isotope', {
84 | layoutMode: 'masonry',
85 | isJQueryFiltering: true,
86 | sortAscending: true,
87 | } );
88 |
89 | Isotope.Item = Item;
90 | Isotope.LayoutMode = LayoutMode;
91 |
92 | var proto = Isotope.prototype;
93 |
94 | proto._create = function() {
95 | this.itemGUID = 0;
96 | // functions that sort items
97 | this._sorters = {};
98 | this._getSorters();
99 | // call super
100 | Outlayer.prototype._create.call( this );
101 |
102 | // create layout modes
103 | this.modes = {};
104 | // start filteredItems with all items
105 | this.filteredItems = this.items;
106 | // keep of track of sortBys
107 | this.sortHistory = [ 'original-order' ];
108 | // create from registered layout modes
109 | for ( var name in LayoutMode.modes ) {
110 | this._initLayoutMode( name );
111 | }
112 | };
113 |
114 | proto.reloadItems = function() {
115 | // reset item ID counter
116 | this.itemGUID = 0;
117 | // call super
118 | Outlayer.prototype.reloadItems.call( this );
119 | };
120 |
121 | proto._itemize = function() {
122 | var items = Outlayer.prototype._itemize.apply( this, arguments );
123 | // assign ID for original-order
124 | for ( var i = 0; i < items.length; i++ ) {
125 | var item = items[i];
126 | item.id = this.itemGUID++;
127 | }
128 | this._updateItemsSortData( items );
129 | return items;
130 | };
131 |
132 | // -------------------------- layout -------------------------- //
133 |
134 | proto._initLayoutMode = function( name ) {
135 | var Mode = LayoutMode.modes[ name ];
136 | // set mode options
137 | // HACK extend initial options, back-fill in default options
138 | var initialOpts = this.options[ name ] || {};
139 | this.options[ name ] = Mode.options ?
140 | utils.extend( Mode.options, initialOpts ) : initialOpts;
141 | // init layout mode instance
142 | this.modes[ name ] = new Mode( this );
143 | };
144 |
145 | proto.layout = function() {
146 | // if first time doing layout, do all magic
147 | if ( !this._isLayoutInited && this._getOption('initLayout') ) {
148 | this.arrange();
149 | return;
150 | }
151 | this._layout();
152 | };
153 |
154 | // private method to be used in layout() & magic()
155 | proto._layout = function() {
156 | // don't animate first layout
157 | var isInstant = this._getIsInstant();
158 | // layout flow
159 | this._resetLayout();
160 | this._manageStamps();
161 | this.layoutItems( this.filteredItems, isInstant );
162 |
163 | // flag for initalized
164 | this._isLayoutInited = true;
165 | };
166 |
167 | // filter + sort + layout
168 | proto.arrange = function( opts ) {
169 | // set any options pass
170 | this.option( opts );
171 | this._getIsInstant();
172 | // filter, sort, and layout
173 |
174 | // filter
175 | var filtered = this._filter( this.items );
176 | this.filteredItems = filtered.matches;
177 |
178 | this._bindArrangeComplete();
179 |
180 | if ( this._isInstant ) {
181 | this._noTransition( this._hideReveal, [ filtered ] );
182 | } else {
183 | this._hideReveal( filtered );
184 | }
185 |
186 | this._sort();
187 | this._layout();
188 | };
189 | // alias to _init for main plugin method
190 | proto._init = proto.arrange;
191 |
192 | proto._hideReveal = function( filtered ) {
193 | this.reveal( filtered.needReveal );
194 | this.hide( filtered.needHide );
195 | };
196 |
197 | // HACK
198 | // Don't animate/transition first layout
199 | // Or don't animate/transition other layouts
200 | proto._getIsInstant = function() {
201 | var isLayoutInstant = this._getOption('layoutInstant');
202 | var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
203 | !this._isLayoutInited;
204 | this._isInstant = isInstant;
205 | return isInstant;
206 | };
207 |
208 | // listen for layoutComplete, hideComplete and revealComplete
209 | // to trigger arrangeComplete
210 | proto._bindArrangeComplete = function() {
211 | // listen for 3 events to trigger arrangeComplete
212 | var isLayoutComplete, isHideComplete, isRevealComplete;
213 | var _this = this;
214 | function arrangeParallelCallback() {
215 | if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
216 | _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
217 | }
218 | }
219 | this.once( 'layoutComplete', function() {
220 | isLayoutComplete = true;
221 | arrangeParallelCallback();
222 | } );
223 | this.once( 'hideComplete', function() {
224 | isHideComplete = true;
225 | arrangeParallelCallback();
226 | } );
227 | this.once( 'revealComplete', function() {
228 | isRevealComplete = true;
229 | arrangeParallelCallback();
230 | } );
231 | };
232 |
233 | // -------------------------- filter -------------------------- //
234 |
235 | proto._filter = function( items ) {
236 | var filter = this.options.filter;
237 | filter = filter || '*';
238 | var matches = [];
239 | var hiddenMatched = [];
240 | var visibleUnmatched = [];
241 |
242 | var test = this._getFilterTest( filter );
243 |
244 | // test each item
245 | for ( var i = 0; i < items.length; i++ ) {
246 | var item = items[i];
247 | if ( item.isIgnored ) {
248 | continue;
249 | }
250 | // add item to either matched or unmatched group
251 | var isMatched = test( item );
252 | // item.isFilterMatched = isMatched;
253 | // add to matches if its a match
254 | if ( isMatched ) {
255 | matches.push( item );
256 | }
257 | // add to additional group if item needs to be hidden or revealed
258 | if ( isMatched && item.isHidden ) {
259 | hiddenMatched.push( item );
260 | } else if ( !isMatched && !item.isHidden ) {
261 | visibleUnmatched.push( item );
262 | }
263 | }
264 |
265 | // return collections of items to be manipulated
266 | return {
267 | matches: matches,
268 | needReveal: hiddenMatched,
269 | needHide: visibleUnmatched,
270 | };
271 | };
272 |
273 | // get a jQuery, function, or a matchesSelector test given the filter
274 | proto._getFilterTest = function( filter ) {
275 | if ( jQuery && this.options.isJQueryFiltering ) {
276 | // use jQuery
277 | return function( item ) {
278 | return jQuery( item.element ).is( filter );
279 | };
280 | }
281 | if ( typeof filter == 'function' ) {
282 | // use filter as function
283 | return function( item ) {
284 | return filter( item.element );
285 | };
286 | }
287 | // default, use filter as selector string
288 | return function( item ) {
289 | return matchesSelector( item.element, filter );
290 | };
291 | };
292 |
293 | // -------------------------- sorting -------------------------- //
294 |
295 | /**
296 | * @param {Array} elems
297 | */
298 | proto.updateSortData = function( elems ) {
299 | // get items
300 | var items;
301 | if ( elems ) {
302 | elems = utils.makeArray( elems );
303 | items = this.getItems( elems );
304 | } else {
305 | // update all items if no elems provided
306 | items = this.items;
307 | }
308 |
309 | this._getSorters();
310 | this._updateItemsSortData( items );
311 | };
312 |
313 | // ----- munge sorter ----- //
314 |
315 | // encapsulate this, as we just need mungeSorter
316 | // other functions in here are just for munging
317 | var mungeSorter = ( function() {
318 | // add a magic layer to sorters for convienent shorthands
319 | // `.foo-bar` will use the text of .foo-bar querySelector
320 | // `[foo-bar]` will use attribute
321 | // you can also add parser
322 | // `.foo-bar parseInt` will parse that as a number
323 | function mngSorter( sorter ) {
324 | // if not a string, return function or whatever it is
325 | if ( typeof sorter != 'string' ) {
326 | return sorter;
327 | }
328 | // parse the sorter string
329 | var args = trim( sorter ).split(' ');
330 | var query = args[0];
331 | // check if query looks like [an-attribute]
332 | var attrMatch = query.match( /^\[(.+)\]$/ );
333 | var attr = attrMatch && attrMatch[1];
334 | var getValue = getValueGetter( attr, query );
335 | // use second argument as a parser
336 | var parser = Isotope.sortDataParsers[ args[1] ];
337 | // parse the value, if there was a parser
338 | sorter = parser ? function( elem ) {
339 | return elem && parser( getValue( elem ) );
340 | } :
341 | // otherwise just return value
342 | function( elem ) {
343 | return elem && getValue( elem );
344 | };
345 |
346 | return sorter;
347 | }
348 |
349 | // get an attribute getter, or get text of the querySelector
350 | function getValueGetter( attr, query ) {
351 | // if query looks like [foo-bar], get attribute
352 | if ( attr ) {
353 | return function getAttribute( elem ) {
354 | return elem.getAttribute( attr );
355 | };
356 | }
357 |
358 | // otherwise, assume its a querySelector, and get its text
359 | return function getChildText( elem ) {
360 | var child = elem.querySelector( query );
361 | return child && child.textContent;
362 | };
363 | }
364 |
365 | return mngSorter;
366 | } )();
367 |
368 | proto._getSorters = function() {
369 | var getSortData = this.options.getSortData;
370 | for ( var key in getSortData ) {
371 | var sorter = getSortData[ key ];
372 | this._sorters[ key ] = mungeSorter( sorter );
373 | }
374 | };
375 |
376 | /**
377 | * @param {Array} items - of Isotope.Items
378 | */
379 | proto._updateItemsSortData = function( items ) {
380 | // do not update if no items
381 | var len = items && items.length;
382 | if ( !len ) {
383 | return;
384 | }
385 |
386 | for ( var i = 0; i < len; i++ ) {
387 | var item = items[i];
388 | item.updateSortData();
389 | }
390 | };
391 |
392 | // parsers used in getSortData shortcut strings
393 | Isotope.sortDataParsers = {
394 | parseInt: function( val ) {
395 | return parseInt( val, 10 );
396 | },
397 | parseFloat: function( val ) {
398 | return parseFloat( val );
399 | },
400 | };
401 |
402 | // ----- sort method ----- //
403 |
404 | // sort filteredItem order
405 | proto._sort = function() {
406 | if ( !this.options.sortBy ) {
407 | return;
408 | }
409 | // keep track of sortBy History
410 | var sortBys = utils.makeArray( this.options.sortBy );
411 | if ( !this._getIsSameSortBy( sortBys ) ) {
412 | // concat all sortBy and sortHistory, add to front, oldest goes in last
413 | this.sortHistory = sortBys.concat( this.sortHistory );
414 | }
415 | // sort magic
416 | var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
417 | this.filteredItems.sort( itemSorter );
418 | };
419 |
420 | // check if sortBys is same as start of sortHistory
421 | proto._getIsSameSortBy = function( sortBys ) {
422 | for ( var i = 0; i < sortBys.length; i++ ) {
423 | if ( sortBys[i] != this.sortHistory[i] ) {
424 | return false;
425 | }
426 | }
427 | return true;
428 | };
429 |
430 | // returns a function used for sorting
431 | function getItemSorter( sortBys, sortAsc ) {
432 | return function sorter( itemA, itemB ) {
433 | // cycle through all sortKeys
434 | for ( var i = 0; i < sortBys.length; i++ ) {
435 | var sortBy = sortBys[i];
436 | var a = itemA.sortData[ sortBy ];
437 | var b = itemB.sortData[ sortBy ];
438 | if ( a > b || a < b ) {
439 | // if sortAsc is an object, use the value given the sortBy key
440 | var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
441 | var direction = isAscending ? 1 : -1;
442 | return ( a > b ? 1 : -1 ) * direction;
443 | }
444 | }
445 | return 0;
446 | };
447 | }
448 |
449 | // -------------------------- methods -------------------------- //
450 |
451 | // get layout mode
452 | proto._mode = function() {
453 | var layoutMode = this.options.layoutMode;
454 | var mode = this.modes[ layoutMode ];
455 | if ( !mode ) {
456 | // TODO console.error
457 | throw new Error( 'No layout mode: ' + layoutMode );
458 | }
459 | // HACK sync mode's options
460 | // any options set after init for layout mode need to be synced
461 | mode.options = this.options[ layoutMode ];
462 | return mode;
463 | };
464 |
465 | proto._resetLayout = function() {
466 | // trigger original reset layout
467 | Outlayer.prototype._resetLayout.call( this );
468 | this._mode()._resetLayout();
469 | };
470 |
471 | proto._getItemLayoutPosition = function( item ) {
472 | return this._mode()._getItemLayoutPosition( item );
473 | };
474 |
475 | proto._manageStamp = function( stamp ) {
476 | this._mode()._manageStamp( stamp );
477 | };
478 |
479 | proto._getContainerSize = function() {
480 | return this._mode()._getContainerSize();
481 | };
482 |
483 | proto.needsResizeLayout = function() {
484 | return this._mode().needsResizeLayout();
485 | };
486 |
487 | // -------------------------- adding & removing -------------------------- //
488 |
489 | // HEADS UP overwrites default Outlayer appended
490 | proto.appended = function( elems ) {
491 | var items = this.addItems( elems );
492 | if ( !items.length ) {
493 | return;
494 | }
495 | // filter, layout, reveal new items
496 | var filteredItems = this._filterRevealAdded( items );
497 | // add to filteredItems
498 | this.filteredItems = this.filteredItems.concat( filteredItems );
499 | };
500 |
501 | // HEADS UP overwrites default Outlayer prepended
502 | proto.prepended = function( elems ) {
503 | var items = this._itemize( elems );
504 | if ( !items.length ) {
505 | return;
506 | }
507 | // start new layout
508 | this._resetLayout();
509 | this._manageStamps();
510 | // filter, layout, reveal new items
511 | var filteredItems = this._filterRevealAdded( items );
512 | // layout previous items
513 | this.layoutItems( this.filteredItems );
514 | // add to items and filteredItems
515 | this.filteredItems = filteredItems.concat( this.filteredItems );
516 | this.items = items.concat( this.items );
517 | };
518 |
519 | proto._filterRevealAdded = function( items ) {
520 | var filtered = this._filter( items );
521 | this.hide( filtered.needHide );
522 | // reveal all new items
523 | this.reveal( filtered.matches );
524 | // layout new items, no transition
525 | this.layoutItems( filtered.matches, true );
526 | return filtered.matches;
527 | };
528 |
529 | /**
530 | * Filter, sort, and layout newly-appended item elements
531 | * @param {[Array, NodeList, Element]} elems
532 | */
533 | proto.insert = function( elems ) {
534 | var items = this.addItems( elems );
535 | if ( !items.length ) {
536 | return;
537 | }
538 | // append item elements
539 | var i, item;
540 | var len = items.length;
541 | for ( i = 0; i < len; i++ ) {
542 | item = items[i];
543 | this.element.appendChild( item.element );
544 | }
545 | // filter new stuff
546 | var filteredInsertItems = this._filter( items ).matches;
547 | // set flag
548 | for ( i = 0; i < len; i++ ) {
549 | items[i].isLayoutInstant = true;
550 | }
551 | this.arrange();
552 | // reset flag
553 | for ( i = 0; i < len; i++ ) {
554 | delete items[i].isLayoutInstant;
555 | }
556 | this.reveal( filteredInsertItems );
557 | };
558 |
559 | var _remove = proto.remove;
560 | proto.remove = function( elems ) {
561 | elems = utils.makeArray( elems );
562 | var removeItems = this.getItems( elems );
563 | // do regular thing
564 | _remove.call( this, elems );
565 | // bail if no items to remove
566 | var len = removeItems && removeItems.length;
567 | // remove elems from filteredItems
568 | if ( !len ) {
569 | return;
570 | }
571 | for ( var i = 0; i < len; i++ ) {
572 | var item = removeItems[i];
573 | // remove item from collection
574 | utils.removeFrom( this.filteredItems, item );
575 | }
576 | };
577 |
578 | proto.shuffle = function() {
579 | // update random sortData
580 | for ( var i = 0; i < this.items.length; i++ ) {
581 | var item = this.items[i];
582 | item.sortData.random = Math.random();
583 | }
584 | this.options.sortBy = 'random';
585 | this._sort();
586 | this._layout();
587 | };
588 |
589 | /**
590 | * trigger fn without transition
591 | * kind of hacky to have this in the first place
592 | * @param {Function} fn
593 | * @param {Array} args
594 | * @returns {Object} returnValue
595 | * @private
596 | */
597 | proto._noTransition = function( fn, args ) {
598 | // save transitionDuration before disabling
599 | var transitionDuration = this.options.transitionDuration;
600 | // disable transition
601 | this.options.transitionDuration = 0;
602 | // do it
603 | var returnValue = fn.apply( this, args );
604 | // re-enable transition for reveal
605 | this.options.transitionDuration = transitionDuration;
606 | return returnValue;
607 | };
608 |
609 | // ----- helper methods ----- //
610 |
611 | /**
612 | * getter method for getting filtered item elements
613 | * @returns {Array} elems - collection of item elements
614 | */
615 | proto.getFilteredItemElements = function() {
616 | return this.filteredItems.map( function( item ) {
617 | return item.element;
618 | } );
619 | };
620 |
621 | // ----- ----- //
622 |
623 | return Isotope;
624 |
625 | } ) );
626 |
--------------------------------------------------------------------------------
/dist/isotope.pkgd.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Isotope PACKAGED v3.0.6
3 | *
4 | * Licensed GPLv3 for open source use
5 | * or Isotope Commercial License for commercial use
6 | *
7 | * https://isotope.metafizzy.co
8 | * Copyright 2010-2018 Metafizzy
9 | */
10 |
11 | !function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,s,a){function u(t,e,o){var n,s="$()."+i+'("'+e+'")';return t.each(function(t,u){var h=a.data(u,i);if(!h)return void r(i+" not initialized. Cannot call methods, i.e. "+s);var d=h[e];if(!d||"_"==e.charAt(0))return void r(s+" is not a valid method");var l=d.apply(h,o);n=void 0===n?l:n}),void 0!==n?n:t}function h(t,e){t.each(function(t,o){var n=a.data(o,i);n?(n.option(e),n._init()):(n=new s(o,e),a.data(o,i,n))})}a=a||e||t.jQuery,a&&(s.prototype.option||(s.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=n.call(arguments,1);return u(this,t,e)}return h(this,t),this},o(a))}function o(t){!t||t&&t.bridget||(t.bridget=i)}var n=Array.prototype.slice,s=t.console,r="undefined"==typeof s?function(){}:function(t){s.error(t)};return o(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},o=i[t]=i[t]||[];return o.indexOf(e)==-1&&o.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},o=i[t]=i[t]||{};return o[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var o=i.indexOf(e);return o!=-1&&i.splice(o,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var o=this._onceEvents&&this._onceEvents[t],n=0;n1&&i+t>this.cols;i=o?0:i;var n=e.size.outerWidth&&e.size.outerHeight;return this.horizontalColIndex=n?i+t:this.horizontalColIndex,{col:i,y:this._getColGroupY(i,t)}},o._manageStamp=function(t){var i=e(t),o=this._getElementOffset(t),n=this._getOption("originLeft"),s=n?o.left:o.right,r=s+i.outerWidth,a=Math.floor(s/this.columnWidth);a=Math.max(0,a);var u=Math.floor(r/this.columnWidth);u-=r%this.columnWidth?0:1,u=Math.min(this.cols-1,u);for(var h=this._getOption("originTop"),d=(h?o.top:o.bottom)+i.outerHeight,l=a;l<=u;l++)this.colYs[l]=Math.max(d,this.colYs[l])},o._getContainerSize=function(){this.maxY=Math.max.apply(Math,this.colYs);var t={height:this.maxY};return this._getOption("fitWidth")&&(t.width=this._getContainerFitWidth()),t},o._getContainerFitWidth=function(){for(var t=0,e=this.cols;--e&&0===this.colYs[e];)t++;return(this.cols-t)*this.columnWidth-this.gutter},o.needsResizeLayout=function(){var t=this.containerWidth;return this.getContainerWidth(),t!=this.containerWidth},i}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-modes/masonry",["../layout-mode","masonry-layout/masonry"],e):"object"==typeof module&&module.exports?module.exports=e(require("../layout-mode"),require("masonry-layout")):e(t.Isotope.LayoutMode,t.Masonry)}(window,function(t,e){"use strict";var i=t.create("masonry"),o=i.prototype,n={_getElementOffset:!0,layout:!0,_getMeasurement:!0};for(var s in e.prototype)n[s]||(o[s]=e.prototype[s]);var r=o.measureColumns;o.measureColumns=function(){this.items=this.isotope.filteredItems,r.call(this)};var a=o._getOption;return o._getOption=function(t){return"fitWidth"==t?void 0!==this.options.isFitWidth?this.options.isFitWidth:this.options.fitWidth:a.apply(this.isotope,arguments)},i}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-modes/fit-rows",["../layout-mode"],e):"object"==typeof exports?module.exports=e(require("../layout-mode")):e(t.Isotope.LayoutMode)}(window,function(t){"use strict";var e=t.create("fitRows"),i=e.prototype;return i._resetLayout=function(){this.x=0,this.y=0,this.maxY=0,this._getMeasurement("gutter","outerWidth")},i._getItemLayoutPosition=function(t){t.getSize();var e=t.size.outerWidth+this.gutter,i=this.isotope.size.innerWidth+this.gutter;0!==this.x&&e+this.x>i&&(this.x=0,this.y=this.maxY);var o={x:this.x,y:this.y};return this.maxY=Math.max(this.maxY,this.y+t.size.outerHeight),this.x+=e,o},i._getContainerSize=function(){return{height:this.maxY}},e}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-modes/vertical",["../layout-mode"],e):"object"==typeof module&&module.exports?module.exports=e(require("../layout-mode")):e(t.Isotope.LayoutMode)}(window,function(t){"use strict";var e=t.create("vertical",{horizontalAlignment:0}),i=e.prototype;return i._resetLayout=function(){this.y=0},i._getItemLayoutPosition=function(t){t.getSize();var e=(this.isotope.size.innerWidth-t.size.outerWidth)*this.options.horizontalAlignment,i=this.y;return this.y+=t.size.outerHeight,{x:e,y:i}},i._getContainerSize=function(){return{height:this.y}},e}),function(t,e){"function"==typeof define&&define.amd?define(["outlayer/outlayer","get-size/get-size","desandro-matches-selector/matches-selector","fizzy-ui-utils/utils","isotope-layout/js/item","isotope-layout/js/layout-mode","isotope-layout/js/layout-modes/masonry","isotope-layout/js/layout-modes/fit-rows","isotope-layout/js/layout-modes/vertical"],function(i,o,n,s,r,a){return e(t,i,o,n,s,r,a)}):"object"==typeof module&&module.exports?module.exports=e(t,require("outlayer"),require("get-size"),require("desandro-matches-selector"),require("fizzy-ui-utils"),require("isotope-layout/js/item"),require("isotope-layout/js/layout-mode"),require("isotope-layout/js/layout-modes/masonry"),require("isotope-layout/js/layout-modes/fit-rows"),require("isotope-layout/js/layout-modes/vertical")):t.Isotope=e(t,t.Outlayer,t.getSize,t.matchesSelector,t.fizzyUIUtils,t.Isotope.Item,t.Isotope.LayoutMode)}(window,function(t,e,i,o,n,s,r){function a(t,e){return function(i,o){for(var n=0;na||ra?1:-1)*h}}return 0}}var u=t.jQuery,h=String.prototype.trim?function(t){return t.trim()}:function(t){return t.replace(/^\s+|\s+$/g,"")},d=e.create("isotope",{layoutMode:"masonry",isJQueryFiltering:!0,sortAscending:!0});d.Item=s,d.LayoutMode=r;var l=d.prototype;l._create=function(){this.itemGUID=0,this._sorters={},this._getSorters(),e.prototype._create.call(this),this.modes={},this.filteredItems=this.items,this.sortHistory=["original-order"];for(var t in r.modes)this._initLayoutMode(t)},l.reloadItems=function(){this.itemGUID=0,e.prototype.reloadItems.call(this)},l._itemize=function(){for(var t=e.prototype._itemize.apply(this,arguments),i=0;i