├── .gitignore
├── .travis.yml
├── src
├── banner.js
├── module-definitions.js
├── target-dom.js
├── config-templates.js
├── transform-data.js
├── ui-class-names.js
├── user-instruction.js
├── command-dataset.js
├── command-remove.js
├── queue-item.js
├── command-change-layout.js
├── mixer-dom.js
├── command-filter.js
├── i-move-data.js
├── command-sort.js
├── command-insert.js
├── command-multimix.js
├── style-data.js
├── transform-defaults.js
├── control-definition.js
├── wrapper.hbs
├── facade.js
├── base-static.js
├── base.js
├── config-behavior.js
├── collection.js
├── operation.js
├── config.js
├── config-selectors.js
├── config-debug.js
├── config-render.js
├── config-load.js
└── config-data.js
├── composer.json
├── .jshintrc
├── tests
├── unit
│ ├── mixer-multimix.js
│ ├── extension.js
│ ├── main.js
│ ├── h.js
│ ├── controls-multimix.js
│ ├── mixer-change-layout.js
│ ├── queue.js
│ ├── mixer-get-config.js
│ ├── controls-sort.js
│ ├── mixer-toggle-on-off.js
│ ├── mixer-get-state.js
│ └── mixer-remove.js
├── mock
│ ├── dataset.json
│ └── extension.js
└── functional
│ └── styles.css
├── demos
├── grid-floats
│ ├── index.html
│ └── style.css
├── grid-flex-box
│ ├── index.html
│ └── style.css
├── grid-inline-block
│ ├── index.html
│ └── style.css
├── sorting-by-default
│ ├── index.html
│ └── style.css
├── toggle-filtering-or-logic
│ ├── index.html
│ └── style.css
├── insertion-non-target-elements
│ ├── index.html
│ └── style.css
├── reset.css
├── toggle-filtering-and-logic
│ ├── index.html
│ └── style.css
├── sorting-by-attribute
│ ├── index.html
│ └── style.css
├── basic
│ ├── index.html
│ └── style.css
├── basic-ie-8
│ ├── index.html
│ └── style.css
├── grid-columns
│ └── index.html
├── sorting-by-multiple-attributes
│ ├── index.html
│ └── style.css
├── multiple-instances-global-control-scoping
│ ├── index.html
│ └── style.css
├── attribute-selectors
│ ├── index.html
│ └── style.css
├── select-dropdowns
│ ├── style.css
│ └── index.html
├── removal-by-reference
│ ├── index.html
│ └── style.css
├── mock-api.js
├── grid-flex-box-matching-heights
│ ├── index.html
│ └── style.css
├── loading-animation
│ ├── index.html
│ └── style.css
├── multiple-instances-local-control-scoping
│ ├── index.html
│ └── style.css
├── checkboxes
│ └── index.html
├── radio-buttons
│ └── index.html
├── filtering-by-url
│ └── style.css
└── index.html
├── package.json
├── docs
├── mixitup.md
├── mixitup.Events.md
└── mixitup-3-migration-guide.md
├── gulpfile.js
├── .jscsrc
└── CHANGELOG.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | components
3 | .tmp
4 | .DS_Store
5 | .log
6 | npm-debug.*
7 | coverage/
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "node"
4 | after_success:
5 | - npm run coveralls
--------------------------------------------------------------------------------
/src/banner.js:
--------------------------------------------------------------------------------
1 | /**!
2 | * {{title}} v{{version}}
3 | * {{description}}
4 | * Build {{buildId}}
5 | *
6 | * @copyright Copyright {{beginCopyrightYear}}-{{currentYear}} {{author}}.
7 | * @author {{author}}.
8 | * @link {{websiteUrl}}
9 | * @license Apache-2.0
10 | */
11 |
--------------------------------------------------------------------------------
/src/module-definitions.js:
--------------------------------------------------------------------------------
1 | /* global module, mixitup, define */
2 |
3 | if (typeof exports === 'object' && typeof module === 'object') {
4 | module.exports = mixitup;
5 | } else if (typeof define === 'function' && define.amd) {
6 | define(function() {
7 | return mixitup;
8 | });
9 | } else if (typeof window.mixitup === 'undefined' || typeof window.mixitup !== 'function') {
10 | window.mixitup = mixitup;
11 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "patrickkunka/mixitup",
3 | "type": "library",
4 | "homepage": "https://github.com/patrickkunka/mixitup/",
5 | "license": "Apache-2.0",
6 | "authors": [
7 | {
8 | "name": "KunkaLabs Limited"
9 | }
10 | ],
11 | "description": "A high-performance, dependency-free library for animated filtering, sorting and more",
12 | "keywords": ["javascript", "animate", "filtering", "sorting"]
13 | }
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true,
3 | "-W030": true,
4 | "-W053": true,
5 | "-W084": true,
6 | "-W055": true,
7 | "-W069": true,
8 | "-W097": true,
9 | "-W087": true,
10 | "undef": true,
11 | "unused": true,
12 | "laxbreak": true,
13 | "node": true,
14 | "browser": true,
15 | "predef": [
16 | "window",
17 | "Promise",
18 | "define",
19 | "console",
20 | "describe",
21 | "after",
22 | "it"
23 | ]
24 | }
--------------------------------------------------------------------------------
/tests/unit/mixer-multimix.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 | chai.use(require('chai-as-promised'));
11 |
12 | describe('mixitup.Mixer', () => {
13 | describe('#multimix()', () => {
14 | let container = dom.getContainer();
15 | let mixer = mixitup(container);
16 | });
17 | });
--------------------------------------------------------------------------------
/src/target-dom.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.TargetDom = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.el = null;
16 |
17 | this.callActions('afterConstruct');
18 |
19 | h.seal(this);
20 | };
21 |
22 | mixitup.BaseStatic.call(mixitup.TargetDom);
23 |
24 | mixitup.TargetDom.prototype = Object.create(mixitup.Base.prototype);
25 |
26 | mixitup.TargetDom.prototype.constructor = mixitup.TargetDom;
--------------------------------------------------------------------------------
/src/config-templates.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.ConfigTemplates = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.callActions('afterConstruct');
16 |
17 | h.seal(this);
18 | };
19 |
20 | mixitup.BaseStatic.call(mixitup.ConfigTemplates);
21 |
22 | mixitup.ConfigTemplates.prototype = Object.create(mixitup.Base.prototype);
23 |
24 | mixitup.ConfigTemplates.prototype.constructor = mixitup.ConfigTemplates;
--------------------------------------------------------------------------------
/tests/unit/extension.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const extension = require('../mock/extension');
8 | const mixitup = require('../../dist/mixitup.js');
9 |
10 | chai.use(require('chai-shallow-deep-equal'));
11 | chai.use(require('chai-as-promised'));
12 |
13 | describe('Extension', () => {
14 | it('should register itself via the mixitup.use() method', () => {
15 | mixitup.use(extension);
16 |
17 | chai.assert.isOk(mixitup.extensions[extension.NAME]);
18 | });
19 | });
--------------------------------------------------------------------------------
/tests/unit/main.js:
--------------------------------------------------------------------------------
1 | require('./factory');
2 | require('./mixer-get-state');
3 | require('./mixer-filter');
4 | require('./mixer-toggle-on-off');
5 | require('./mixer-sort');
6 | require('./mixer-dataset');
7 | require('./mixer-insert');
8 | require('./mixer-remove');
9 | require('./mixer-change-layout');
10 | require('./mixer-multimix');
11 | require('./mixer-get-config');
12 | require('./controls-filter');
13 | require('./controls-toggle');
14 | require('./controls-sort');
15 | require('./controls-multimix');
16 | require('./controls-live');
17 | require('./queue');
18 | require('./extension');
19 | require('./callbacks');
20 | require('./h');
--------------------------------------------------------------------------------
/src/transform-data.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.TransformData = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.value = 0;
16 | this.unit = '';
17 |
18 | this.callActions('afterConstruct');
19 |
20 | h.seal(this);
21 | };
22 |
23 | mixitup.BaseStatic.call(mixitup.TransformData);
24 |
25 | mixitup.TransformData.prototype = Object.create(mixitup.Base.prototype);
26 |
27 | mixitup.TransformData.prototype.constructor = mixitup.TransformData;
--------------------------------------------------------------------------------
/src/ui-class-names.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.UiClassNames = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.base = '';
16 | this.active = '';
17 | this.disabled = '';
18 |
19 | this.callActions('afterConstruct');
20 |
21 | h.seal(this);
22 | };
23 |
24 | mixitup.BaseStatic.call(mixitup.UiClassNames);
25 |
26 | mixitup.UiClassNames.prototype = Object.create(mixitup.Base.prototype);
27 |
28 | mixitup.UiClassNames.prototype.constructor = mixitup.UiClassNames;
--------------------------------------------------------------------------------
/src/user-instruction.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.UserInstruction = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.command = {};
16 | this.animate = false;
17 | this.callback = null;
18 |
19 | this.callActions('afterConstruct');
20 |
21 | h.seal(this);
22 | };
23 |
24 | mixitup.BaseStatic.call(mixitup.UserInstruction);
25 |
26 | mixitup.UserInstruction.prototype = Object.create(mixitup.Base.prototype);
27 |
28 | mixitup.UserInstruction.prototype.constructor = mixitup.UserInstruction;
--------------------------------------------------------------------------------
/src/command-dataset.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.dataset()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandDataset = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.dataset = null;
18 |
19 | this.callActions('afterConstruct');
20 |
21 | h.seal(this);
22 | };
23 |
24 | mixitup.BaseStatic.call(mixitup.CommandDataset);
25 |
26 | mixitup.CommandDataset.prototype = Object.create(mixitup.Base.prototype);
27 |
28 | mixitup.CommandDataset.prototype.constructor = mixitup.CommandDataset;
--------------------------------------------------------------------------------
/src/command-remove.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.remove()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandRemove = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.targets = [];
18 | this.collection = [];
19 |
20 | this.callActions('afterConstruct');
21 |
22 | h.seal(this);
23 | };
24 |
25 | mixitup.BaseStatic.call(mixitup.CommandRemove);
26 |
27 | mixitup.CommandRemove.prototype = Object.create(mixitup.Base.prototype);
28 |
29 | mixitup.CommandRemove.prototype.constructor = mixitup.CommandRemove;
--------------------------------------------------------------------------------
/src/queue-item.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.QueueItem = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.args = [];
16 | this.instruction = null;
17 | this.triggerElement = null;
18 | this.deferred = null;
19 | this.isToggling = false;
20 |
21 | this.callActions('afterConstruct');
22 |
23 | h.seal(this);
24 | };
25 |
26 | mixitup.BaseStatic.call(mixitup.QueueItem);
27 |
28 | mixitup.QueueItem.prototype = Object.create(mixitup.Base.prototype);
29 |
30 | mixitup.QueueItem.prototype.constructor = mixitup.QueueItem;
--------------------------------------------------------------------------------
/demos/grid-floats/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Float-based Grid
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/command-change-layout.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.changeLayout()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandChangeLayout = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.containerClassName = '';
18 |
19 | this.callActions('afterConstruct');
20 |
21 | h.seal(this);
22 | };
23 |
24 | mixitup.BaseStatic.call(mixitup.CommandChangeLayout);
25 |
26 | mixitup.CommandChangeLayout.prototype = Object.create(mixitup.Base.prototype);
27 |
28 | mixitup.CommandChangeLayout.prototype.constructor = mixitup.CommandChangeLayout;
--------------------------------------------------------------------------------
/src/mixer-dom.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.MixerDom = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.document = null;
16 | this.body = null;
17 | this.container = null;
18 | this.parent = null;
19 | this.targets = [];
20 |
21 | this.callActions('afterConstruct');
22 |
23 | h.seal(this);
24 | };
25 |
26 | mixitup.BaseStatic.call(mixitup.MixerDom);
27 |
28 | mixitup.MixerDom.prototype = Object.create(mixitup.Base.prototype);
29 |
30 | mixitup.MixerDom.prototype.constructor = mixitup.MixerDom;
--------------------------------------------------------------------------------
/src/command-filter.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.filter()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandFilter = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.selector = '';
18 | this.collection = null;
19 | this.action = 'show'; // enum: ['show', 'hide']
20 |
21 | this.callActions('afterConstruct');
22 |
23 | h.seal(this);
24 | };
25 |
26 | mixitup.BaseStatic.call(mixitup.CommandFilter);
27 |
28 | mixitup.CommandFilter.prototype = Object.create(mixitup.Base.prototype);
29 |
30 | mixitup.CommandFilter.prototype.constructor = mixitup.CommandFilter;
--------------------------------------------------------------------------------
/src/i-move-data.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.IMoveData = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.posIn = null;
16 | this.posOut = null;
17 | this.operation = null;
18 | this.callback = null;
19 | this.statusChange = '';
20 | this.duration = -1;
21 | this.staggerIndex = -1;
22 |
23 | this.callActions('afterConstruct');
24 |
25 | h.seal(this);
26 | };
27 |
28 | mixitup.BaseStatic.call(mixitup.IMoveData);
29 |
30 | mixitup.IMoveData.prototype = Object.create(mixitup.Base.prototype);
31 |
32 | mixitup.IMoveData.prototype.constructor = mixitup.IMoveData;
--------------------------------------------------------------------------------
/src/command-sort.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.sort()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandSort = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.sortString = '';
18 | this.attribute = '';
19 | this.order = 'asc';
20 | this.collection = null;
21 | this.next = null;
22 |
23 | this.callActions('afterConstruct');
24 |
25 | h.seal(this);
26 | };
27 |
28 | mixitup.BaseStatic.call(mixitup.CommandSort);
29 |
30 | mixitup.CommandSort.prototype = Object.create(mixitup.Base.prototype);
31 |
32 | mixitup.CommandSort.prototype.constructor = mixitup.CommandSort;
--------------------------------------------------------------------------------
/src/command-insert.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.insert()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandInsert = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.index = 0;
18 | this.collection = [];
19 | this.position = 'before'; // enum: ['before', 'after']
20 | this.sibling = null;
21 |
22 | this.callActions('afterConstruct');
23 |
24 | h.seal(this);
25 | };
26 |
27 | mixitup.BaseStatic.call(mixitup.CommandInsert);
28 |
29 | mixitup.CommandInsert.prototype = Object.create(mixitup.Base.prototype);
30 |
31 | mixitup.CommandInsert.prototype.constructor = mixitup.CommandInsert;
--------------------------------------------------------------------------------
/src/command-multimix.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * An object into which all arbitrary arguments sent to '.multimix()' are mapped.
5 | *
6 | * @constructor
7 | * @memberof mixitup
8 | * @private
9 | * @since 3.0.0
10 | */
11 |
12 | mixitup.CommandMultimix = function() {
13 | mixitup.Base.call(this);
14 |
15 | this.callActions('beforeConstruct');
16 |
17 | this.filter = null;
18 | this.sort = null;
19 | this.insert = null;
20 | this.remove = null;
21 | this.changeLayout = null;
22 |
23 | this.callActions('afterConstruct');
24 |
25 | h.seal(this);
26 | };
27 |
28 | mixitup.BaseStatic.call(mixitup.CommandMultimix);
29 |
30 | mixitup.CommandMultimix.prototype = Object.create(mixitup.Base.prototype);
31 |
32 | mixitup.CommandMultimix.prototype.constructor = mixitup.CommandMultimix;
--------------------------------------------------------------------------------
/demos/grid-flex-box/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Flex-box Grid
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demos/grid-inline-block/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Inline-block Grid
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/tests/mock/dataset.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "target-1",
4 | "categories": ["a"],
5 | "published": "20161102",
6 | "views": 100
7 | },
8 | {
9 | "id": "target-2",
10 | "categories": ["a"],
11 | "published": "20130501",
12 | "views": 54
13 | },
14 | {
15 | "id": "target-3",
16 | "categories": ["b"],
17 | "published": "20121231",
18 | "views": 3
19 | },
20 | {
21 | "id": "target-4",
22 | "categories": ["b"],
23 | "published": "20160407",
24 | "views": 62
25 | },
26 | {
27 | "id": "target-5",
28 | "categories": ["c"],
29 | "published": "20160820",
30 | "views": 54
31 | },
32 | {
33 | "id": "target-6",
34 | "categories": ["a", "c"],
35 | "published": "20151020",
36 | "views": 95
37 | }
38 | ]
--------------------------------------------------------------------------------
/src/style-data.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.StyleData = function() {
11 | mixitup.Base.call(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.x = 0;
16 | this.y = 0;
17 | this.top = 0;
18 | this.right = 0;
19 | this.bottom = 0;
20 | this.left = 0;
21 | this.width = 0;
22 | this.height = 0;
23 | this.marginRight = 0;
24 | this.marginBottom = 0;
25 | this.opacity = 0;
26 | this.scale = new mixitup.TransformData();
27 | this.translateX = new mixitup.TransformData();
28 | this.translateY = new mixitup.TransformData();
29 | this.translateZ = new mixitup.TransformData();
30 | this.rotateX = new mixitup.TransformData();
31 | this.rotateY = new mixitup.TransformData();
32 | this.rotateZ = new mixitup.TransformData();
33 |
34 | this.callActions('afterConstruct');
35 |
36 | h.seal(this);
37 | };
38 |
39 | mixitup.BaseStatic.call(mixitup.StyleData);
40 |
41 | mixitup.StyleData.prototype = Object.create(mixitup.Base.prototype);
42 |
43 | mixitup.StyleData.prototype.constructor = mixitup.StyleData;
--------------------------------------------------------------------------------
/demos/sorting-by-default/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Sorting by Default
10 |
11 |
12 |
13 | Asc
14 | Desc
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mixitup",
3 | "title": "MixItUp",
4 | "version": "3.3.2",
5 | "description": "A high-performance, dependency-free library for animated filtering, sorting and more",
6 | "author": "KunkaLabs Limited",
7 | "license": "Apache-2.0",
8 | "main": "./dist/mixitup.js",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/patrickkunka/mixitup/"
12 | },
13 | "scripts": {
14 | "test": "mocha ./tests/unit/main.js",
15 | "cover": "istanbul cover _mocha ./tests/unit/main.js",
16 | "coveralls": "npm run cover -- --report lcovonly && cat ./coverage/lcov.info | coveralls"
17 | },
18 | "devDependencies": {
19 | "chai": "^3.5.0",
20 | "chai-as-promised": "^5.3.0",
21 | "chai-shallow-deep-equal": "^1.4.0",
22 | "coveralls": "^2.11.14",
23 | "gulp": "^3.8.8",
24 | "gulp-jscs": "^4.0.0",
25 | "gulp-jshint": "^1.8.5",
26 | "gulp-livereload": "~2.1.1",
27 | "gulp-rename": "^1.2.2",
28 | "gulp-uglify": "~1.5.1",
29 | "istanbul": "^0.4.5",
30 | "jsdom": "9.4.2",
31 | "jsdom-global": "2.0.0",
32 | "jshint-stylish": "~1.0.0",
33 | "merge-stream": "^0.1.7",
34 | "mixitup-build": "git://github.com/patrickkunka/mixitup-build.git",
35 | "mocha": "^3.0.2",
36 | "mocha-lcov-reporter": "^1.2.0",
37 | "vinyl-buffer": "^1.0.0",
38 | "vinyl-source-stream": "^1.1.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/unit/h.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const chai = require('chai');
4 | const mixitup = require('../../dist/mixitup.js');
5 |
6 | const h = mixitup.h;
7 |
8 | describe('h#compareVersions()', () => {
9 | it('should return true if versions are matching', () => {
10 | let result = h.compareVersions('1.0.0', '1.0.0');
11 |
12 | chai.assert.isOk(result);
13 | });
14 |
15 | it('should return false if specimen version is less than control', () => {
16 | let result = h.compareVersions('1.0.0', '0.1.2');
17 |
18 | chai.assert.isNotOk(result);
19 | });
20 |
21 | it('should return true if specimen version is greater than control', () => {
22 | let result = h.compareVersions('1.0.0', '1.1.2');
23 |
24 | chai.assert.isOk(result);
25 | });
26 |
27 | it('should return true if specimen version is greater than control, with double figures', () => {
28 | let result = h.compareVersions('3.0.0', '10.1.2');
29 |
30 | chai.assert.isOk(result);
31 | });
32 |
33 | it('should handle semver carat notation', () => {
34 | let result = h.compareVersions('^3.0.0', '2.0.0');
35 |
36 | chai.assert.isNotOk(result);
37 | });
38 |
39 | it('should handle semver label notation', () => {
40 | let result = h.compareVersions('^3.0.0', '3.0.0-beta');
41 |
42 | chai.assert.isOk(result);
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/demos/grid-floats/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Container
14 | ---------------------------------------------------------------------- */
15 |
16 | .container {
17 | padding: 1rem .5rem;
18 | overflow: hidden;
19 | }
20 |
21 | /* Target Elements
22 | ---------------------------------------------------------------------- */
23 |
24 | .mix {
25 | float: left;
26 | margin: 0 .5rem 1rem;
27 | background: #fff;
28 | border-radius: 2px;
29 | position: relative;
30 | }
31 |
32 | .mix:before {
33 | content: '';
34 | display: inline-block;
35 | padding-top: 56.25%;
36 | }
37 |
38 | /* Grid Breakpoints
39 | ---------------------------------------------------------------------- */
40 |
41 | /* 2 Columns */
42 |
43 | .mix {
44 | width: calc(50% - 1rem);
45 | }
46 |
47 | /* 3 Columns */
48 |
49 | @media screen and (min-width: 541px) {
50 | .mix {
51 | width: calc(100%/3 - 1rem);
52 | }
53 | }
54 |
55 | /* 4 Columns */
56 |
57 | @media screen and (min-width: 961px) {
58 | .mix,
59 | .gap {
60 | width: calc(100%/4 - 1rem);
61 | }
62 | }
63 |
64 | /* 5 Columns */
65 |
66 | @media screen and (min-width: 1281px) {
67 | .mix,
68 | .gap {
69 | width: calc(100%/5 - 1rem);
70 | }
71 | }
72 |
73 |
74 |
--------------------------------------------------------------------------------
/tests/mock/extension.js:
--------------------------------------------------------------------------------
1 | (function(window) {
2 | 'use strict';
3 |
4 | var mixitupMockExtension = function(mixitup) {
5 | var h = mixitup.h;
6 |
7 | if (
8 | !mixitup.CORE_VERSION ||
9 | !h.compareVersions(mixitupMockExtension.REQUIRE_CORE_VERSION, mixitup.CORE_VERSION)
10 | ) {
11 | throw new Error(
12 | '[MixItUp-MockExtension] MixItUp MockExtension v' +
13 | mixitupMockExtension.EXTENSION_VERSION +
14 | ' requires at least MixItUp v' +
15 | mixitupMockExtension.REQUIRE_CORE_VERSION
16 | );
17 | }
18 |
19 | };
20 |
21 | mixitupMockExtension.TYPE = 'mixitup-extension';
22 | mixitupMockExtension.NAME = 'mixitup-mock-extension';
23 | mixitupMockExtension.EXTENSION_VERSION = '1.0.0';
24 | mixitupMockExtension.REQUIRE_CORE_VERSION = '3.0.0';
25 |
26 | if (typeof exports === 'object' && typeof module === 'object') {
27 | module.exports = mixitupMockExtension;
28 | } else if (typeof define === 'function' && define.amd) {
29 | define(function() {
30 | return mixitupMockExtension;
31 | });
32 | } else if (window.mixitup && typeof window.mixitup === 'function') {
33 | mixitupMockExtension(window.mixitup);
34 | } else {
35 | console.error('[MixItUp-MockExtension] MixItUp core not found');
36 | }
37 | })(window);
--------------------------------------------------------------------------------
/src/transform-defaults.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | */
9 |
10 | mixitup.TransformDefaults = function() {
11 | mixitup.StyleData.apply(this);
12 |
13 | this.callActions('beforeConstruct');
14 |
15 | this.scale.value = 0.01;
16 | this.scale.unit = '';
17 |
18 | this.translateX.value = 20;
19 | this.translateX.unit = 'px';
20 |
21 | this.translateY.value = 20;
22 | this.translateY.unit = 'px';
23 |
24 | this.translateZ.value = 20;
25 | this.translateZ.unit = 'px';
26 |
27 | this.rotateX.value = 90;
28 | this.rotateX.unit = 'deg';
29 |
30 | this.rotateY.value = 90;
31 | this.rotateY.unit = 'deg';
32 |
33 | this.rotateX.value = 90;
34 | this.rotateX.unit = 'deg';
35 |
36 | this.rotateZ.value = 180;
37 | this.rotateZ.unit = 'deg';
38 |
39 | this.callActions('afterConstruct');
40 |
41 | h.seal(this);
42 | };
43 |
44 | mixitup.BaseStatic.call(mixitup.TransformDefaults);
45 |
46 | mixitup.TransformDefaults.prototype = Object.create(mixitup.StyleData.prototype);
47 |
48 | mixitup.TransformDefaults.prototype.constructor = mixitup.TransformDefaults;
49 |
50 | /**
51 | * @private
52 | * @static
53 | * @since 3.0.0
54 | * @type {mixitup.TransformDefaults}
55 | */
56 |
57 | mixitup.transformDefaults = new mixitup.TransformDefaults();
--------------------------------------------------------------------------------
/src/control-definition.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | * @param {string} type
9 | * @param {string} selector
10 | * @param {boolean} [live]
11 | * @param {string} [parent]
12 | * An optional string representing the name of the mixer.dom property containing a reference to a parent element.
13 | */
14 |
15 | mixitup.ControlDefinition = function(type, selector, live, parent) {
16 | mixitup.Base.call(this);
17 |
18 | this.callActions('beforeConstruct');
19 |
20 | this.type = type;
21 | this.selector = selector;
22 | this.live = live || false;
23 | this.parent = parent || '';
24 |
25 | this.callActions('afterConstruct');
26 |
27 | h.freeze(this);
28 | h.seal(this);
29 | };
30 |
31 | mixitup.BaseStatic.call(mixitup.ControlDefinition);
32 |
33 | mixitup.ControlDefinition.prototype = Object.create(mixitup.Base.prototype);
34 |
35 | mixitup.ControlDefinition.prototype.constructor = mixitup.ControlDefinition;
36 |
37 | mixitup.controlDefinitions = [];
38 |
39 | mixitup.controlDefinitions.push(new mixitup.ControlDefinition('multimix', '[data-filter][data-sort]'));
40 | mixitup.controlDefinitions.push(new mixitup.ControlDefinition('filter', '[data-filter]'));
41 | mixitup.controlDefinitions.push(new mixitup.ControlDefinition('sort', '[data-sort]'));
42 | mixitup.controlDefinitions.push(new mixitup.ControlDefinition('toggle', '[data-toggle]'));
--------------------------------------------------------------------------------
/demos/toggle-filtering-or-logic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Toggle Filtering OR Logic
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
--------------------------------------------------------------------------------
/demos/insertion-non-target-elements/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Insertion with Non-target Elements
10 |
11 |
12 |
13 | Asc
14 | Desc
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
41 |
42 |
--------------------------------------------------------------------------------
/demos/reset.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, u, i, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video {
14 | margin: 0;
15 | padding: 0;
16 | border: 0;
17 | font-size: 100%;
18 | font: inherit;
19 | vertical-align: baseline;
20 | }
21 |
22 | article, aside, details, figcaption, figure,
23 | footer, header, hgroup, menu, nav, section {
24 | display: block;
25 | }
26 |
27 | body {
28 | line-height: 1;
29 |
30 | -webkit-font-smoothing: antialiased;
31 | -moz-osx-font-smoothing: antialiased;
32 | }
33 |
34 | blockquote, q {
35 | quotes: none;
36 | }
37 |
38 | a {
39 | text-decoration: none;
40 | }
41 |
42 | blockquote:before, blockquote:after,
43 | q:before, q:after {
44 | content: '';
45 | content: none;
46 | }
47 |
48 | button {
49 | background: transparent;
50 | border-radius: 0;
51 | border: 0;
52 | padding: 0;
53 |
54 | -webkit-appearance: none;
55 | -webkit-border-radius: 0;
56 |
57 | user-select: none;
58 | }
59 |
60 | button:focus {
61 | outline: 0 none;
62 | }
63 |
64 | button::-moz-focus-inner {
65 | padding: 0;
66 | border: 0;
67 | }
68 |
69 | table {
70 | border-collapse: collapse;
71 | border-spacing: 0;
72 | }
--------------------------------------------------------------------------------
/demos/grid-flex-box/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Container
14 | ---------------------------------------------------------------------- */
15 |
16 | .container {
17 | padding: 1rem;
18 | display: flex;
19 | flex-direction: row;
20 | flex-wrap: wrap;
21 | align-content: flex-start;
22 | justify-content: space-between;
23 | }
24 |
25 | /* Target Elements
26 | ---------------------------------------------------------------------- */
27 |
28 | .mix,
29 | .gap {
30 | display: inline-block;
31 | vertical-align: top;
32 | }
33 |
34 | .mix {
35 | background: #fff;
36 | border-radius: 2px;
37 | margin-bottom: 1rem;
38 | position: relative;
39 | }
40 |
41 | .mix:before {
42 | content: '';
43 | display: inline-block;
44 | padding-top: 56.25%;
45 | }
46 |
47 | /* Grid Breakpoints
48 | ---------------------------------------------------------------------- */
49 |
50 | /* 2 Columns */
51 |
52 | .mix,
53 | .gap {
54 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
55 | }
56 |
57 | /* 3 Columns */
58 |
59 | @media screen and (min-width: 541px) {
60 | .mix,
61 | .gap {
62 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
63 | }
64 | }
65 |
66 | /* 4 Columns */
67 |
68 | @media screen and (min-width: 961px) {
69 | .mix,
70 | .gap {
71 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
72 | }
73 | }
74 |
75 | /* 5 Columns */
76 |
77 | @media screen and (min-width: 1281px) {
78 | .mix,
79 | .gap {
80 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
81 | }
82 | }
83 |
84 |
85 |
--------------------------------------------------------------------------------
/demos/grid-inline-block/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Container
14 | ---------------------------------------------------------------------- */
15 |
16 | .container {
17 | padding: 1rem;
18 | text-align: justify;
19 | font-size: 0.1px;
20 | }
21 |
22 | .container:after {
23 | content: '';
24 | display: inline-block;
25 | width: 100%;
26 | }
27 |
28 | /* Target Elements
29 | ---------------------------------------------------------------------- */
30 |
31 | .mix,
32 | .gap {
33 | display: inline-block;
34 | vertical-align: top;
35 | }
36 |
37 | .mix {
38 | background: #fff;
39 | border-radius: 2px;
40 | margin-bottom: 1rem;
41 | position: relative;
42 | }
43 |
44 | .mix:before {
45 | content: '';
46 | display: inline-block;
47 | padding-top: 56.25%;
48 | }
49 |
50 | /* Grid Breakpoints
51 | ---------------------------------------------------------------------- */
52 |
53 | /* 2 Columns */
54 |
55 | .mix,
56 | .gap {
57 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
58 | }
59 |
60 | /* 3 Columns */
61 |
62 | @media screen and (min-width: 541px) {
63 | .mix,
64 | .gap {
65 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
66 | }
67 | }
68 |
69 | /* 4 Columns */
70 |
71 | @media screen and (min-width: 961px) {
72 | .mix,
73 | .gap {
74 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
75 | }
76 | }
77 |
78 | /* 5 Columns */
79 |
80 | @media screen and (min-width: 1281px) {
81 | .mix,
82 | .gap {
83 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
84 | }
85 | }
86 |
87 |
88 |
--------------------------------------------------------------------------------
/demos/toggle-filtering-and-logic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Toggle Filtering AND Logic
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/unit/controls-multimix.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 | chai.use(require('chai-as-promised'));
11 |
12 | describe('Controls', () => {
13 | describe('Multimix', () => {
14 | let frag = document.createDocumentFragment();
15 | let container = dom.getContainer();
16 | let controls = dom.getMultimixControls();
17 |
18 | container.insertBefore(controls, container.children[0]);
19 |
20 | frag.appendChild(container);
21 |
22 | let mixer = mixitup(container, {
23 | controls: {
24 | scope: 'local'
25 | }
26 | }, frag);
27 |
28 | after(() => mixer.destroy());
29 |
30 | it('should detect nested filter controls and set active states upon instantiation', () => {
31 | let control = controls.querySelector('[data-filter="all"][data-sort="default:asc"]');
32 |
33 | chai.assert.isOk(control.matches('.mixitup-control-active'));
34 | });
35 |
36 | it('should read filter and sort actions simultaneously', () => {
37 | let control = controls.querySelector('[data-filter=".category-b"][data-sort="published"]');
38 |
39 | control.click();
40 |
41 | let state = mixer.getState();
42 |
43 | chai.assert.equal(state.activeFilter.selector, '.category-b');
44 | chai.assert.equal(state.activeSort.sortString, 'published');
45 |
46 | chai.assert.isOk(control.matches('.mixitup-control-active'));
47 | });
48 | });
49 | });
--------------------------------------------------------------------------------
/demos/sorting-by-attribute/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Sorting by Attribute
10 |
11 |
12 |
13 | Asc
14 | Desc
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
43 |
44 |
--------------------------------------------------------------------------------
/docs/mixitup.md:
--------------------------------------------------------------------------------
1 | #mixitup()
2 |
3 | *Version added: 3.0.0*
4 |
5 | `mixitup(container [,config] [,foreignDoc])`
6 |
7 | The `mixitup()` "factory" function creates and returns individual instances
8 | of MixItUp, known as "mixers", on which API methods can be called.
9 |
10 | When loading MixItUp via a script tag, the factory function is accessed
11 | via the global variable `mixitup`. When using a module loading
12 | system (e.g. ES2015, CommonJS, RequireJS), the factory function is
13 | exported into your module when you require the MixItUp library.
14 |
15 | | |Type | Name | Description
16 | |---|--- | --- | ---
17 | |Param |`Element, string` | `container` | A DOM element or selector string representing the container(s) on which to instantiate MixItUp.
18 | |Param |`object` | `[config]` | An optional "configuration object" used to customize the behavior of the MixItUp instance.
19 | |Param |`object` | `[foreignDoc]` | An optional reference to a `document`, which can be used to control a MixItUp instance in an iframe.
20 | |Returns |`mixitup.Mixer` | A "mixer" object holding the MixItUp instance.
21 |
22 | ###### Example 1: Creating a mixer instance with an element reference
23 |
24 | ```js
25 | var containerEl = document.querySelector('.container');
26 |
27 | var mixer = mixitup(containerEl);
28 | ```
29 | ###### Example 2: Creating a mixer instance with a selector string
30 |
31 | ```js
32 | var mixer = mixitup('.container');
33 | ```
34 | ###### Example 3: Passing a configuration object
35 |
36 | ```js
37 | var mixer = mixitup(containerEl, {
38 | animation: {
39 | effects: 'fade scale(0.5)'
40 | }
41 | });
42 | ```
43 | ###### Example 4: Passing an iframe reference
44 |
45 | ```js
46 | var mixer = mixitup(containerEl, config, foreignDocument);
47 | ```
48 |
--------------------------------------------------------------------------------
/demos/basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Basic
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 | None
18 |
19 | Asc
20 | Desc
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
--------------------------------------------------------------------------------
/demos/basic-ie-8/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Basic (IE8 Compatible Layout)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Asc
20 | Desc
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
--------------------------------------------------------------------------------
/src/wrapper.hbs:
--------------------------------------------------------------------------------
1 | {{>banner}}
2 |
3 | (function(window) {
4 | 'use strict';
5 |
6 | var mixitup = null,
7 | h = null;
8 |
9 | {{>polyfills}}
10 |
11 | {{>factory}}
12 |
13 | {{>h}}
14 |
15 | {{>base}}
16 |
17 | {{>base-static}}
18 |
19 | {{>features}}
20 |
21 | {{>config-animation}}
22 |
23 | {{>config-behavior}}
24 |
25 | {{>config-callbacks}}
26 |
27 | {{>config-controls}}
28 |
29 | {{>config-class-names}}
30 |
31 | {{>config-data}}
32 |
33 | {{>config-debug}}
34 |
35 | {{>config-layout}}
36 |
37 | {{>config-load}}
38 |
39 | {{>config-selectors}}
40 |
41 | {{>config-render}}
42 |
43 | {{>config-templates}}
44 |
45 | {{>config}}
46 |
47 | {{>mixer-dom}}
48 |
49 | {{>ui-class-names}}
50 |
51 | {{>command-dataset}}
52 |
53 | {{>command-multimix}}
54 |
55 | {{>command-filter}}
56 |
57 | {{>command-sort}}
58 |
59 | {{>command-insert}}
60 |
61 | {{>command-remove}}
62 |
63 | {{>command-change-layout}}
64 |
65 | {{>control-definition}}
66 |
67 | {{>control}}
68 |
69 | {{>style-data}}
70 |
71 | {{>transform-data}}
72 |
73 | {{>transform-defaults}}
74 |
75 | {{>events}}
76 |
77 | {{>queue-item}}
78 |
79 | {{>mixer}}
80 |
81 | {{>i-move-data}}
82 |
83 | {{>target-dom}}
84 |
85 | {{>target}}
86 |
87 | {{>collection}}
88 |
89 | {{>operation}}
90 |
91 | {{>state}}
92 |
93 | {{>user-instruction}}
94 |
95 | {{>messages}}
96 |
97 | {{>facade}}
98 |
99 | {{>module-definitions}}
100 |
101 | mixitup.BaseStatic.call(mixitup.constructor);
102 |
103 | mixitup.NAME = '{{name}}';
104 | mixitup.CORE_VERSION = '{{version}}';
105 | })(window);
--------------------------------------------------------------------------------
/src/facade.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * @constructor
5 | * @memberof mixitup
6 | * @private
7 | * @since 3.0.0
8 | * @param {mixitup.Mixer} mixer
9 | */
10 |
11 | mixitup.Facade = function Mixer(mixer) {
12 | mixitup.Base.call(this);
13 |
14 | this.callActions('beforeConstruct', arguments);
15 |
16 | this.configure = mixer.configure.bind(mixer);
17 | this.show = mixer.show.bind(mixer);
18 | this.hide = mixer.hide.bind(mixer);
19 | this.filter = mixer.filter.bind(mixer);
20 | this.toggleOn = mixer.toggleOn.bind(mixer);
21 | this.toggleOff = mixer.toggleOff.bind(mixer);
22 | this.sort = mixer.sort.bind(mixer);
23 | this.changeLayout = mixer.changeLayout.bind(mixer);
24 | this.multimix = mixer.multimix.bind(mixer);
25 | this.dataset = mixer.dataset.bind(mixer);
26 | this.tween = mixer.tween.bind(mixer);
27 | this.insert = mixer.insert.bind(mixer);
28 | this.insertBefore = mixer.insertBefore.bind(mixer);
29 | this.insertAfter = mixer.insertAfter.bind(mixer);
30 | this.prepend = mixer.prepend.bind(mixer);
31 | this.append = mixer.append.bind(mixer);
32 | this.remove = mixer.remove.bind(mixer);
33 | this.destroy = mixer.destroy.bind(mixer);
34 | this.forceRefresh = mixer.forceRefresh.bind(mixer);
35 | this.forceRender = mixer.forceRender.bind(mixer);
36 | this.isMixing = mixer.isMixing.bind(mixer);
37 | this.getOperation = mixer.getOperation.bind(mixer);
38 | this.getConfig = mixer.getConfig.bind(mixer);
39 | this.getState = mixer.getState.bind(mixer);
40 |
41 | this.callActions('afterConstruct', arguments);
42 |
43 | h.freeze(this);
44 | h.seal(this);
45 | };
46 |
47 | mixitup.BaseStatic.call(mixitup.Facade);
48 |
49 | mixitup.Facade.prototype = Object.create(mixitup.Base.prototype);
50 |
51 | mixitup.Facade.prototype.constructor = mixitup.Facade;
--------------------------------------------------------------------------------
/demos/grid-columns/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Columns Grid
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 | None
18 |
19 | Asc
20 | Desc
21 |
22 | Shuffle
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
50 |
51 |
--------------------------------------------------------------------------------
/src/base-static.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * The BaseStatic class holds a set of static methods which are then added to all other
5 | * extensible MixItUp classes as a means of integrating extensions via the addition of new
6 | * methods and/or actions and hooks.
7 | *
8 | * @constructor
9 | * @namespace
10 | * @memberof mixitup
11 | * @private
12 | * @since 3.0.0
13 | */
14 |
15 | mixitup.BaseStatic = function() {
16 | this.actions = {};
17 | this.filters = {};
18 |
19 | /**
20 | * Performs a shallow extend on the class's prototype, adding one or more new members to
21 | * the class in a single operation.
22 | *
23 | * @memberof mixitup.BaseStatic
24 | * @public
25 | * @static
26 | * @since 2.1.0
27 | * @param {object} extension
28 | * @return {void}
29 | */
30 |
31 | this.extend = function(extension) {
32 | h.extend(this.prototype, extension);
33 | };
34 |
35 | /**
36 | * Registers a function to be called on the action hook of the provided name.
37 | *
38 | * @memberof mixitup.BaseStatic
39 | * @public
40 | * @static
41 | * @since 2.1.0
42 | * @param {string} hookName
43 | * @param {string} extensionName
44 | * @param {function} func
45 | * @return {void}
46 | */
47 |
48 | this.registerAction = function(hookName, extensionName, func) {
49 | (this.actions[hookName] = this.actions[hookName] || {})[extensionName] = func;
50 | };
51 |
52 | /**
53 | * Registers a function to be called on the filter of the provided name.
54 | *
55 | * @memberof mixitup.BaseStatic
56 | * @public
57 | * @static
58 | * @since 2.1.0
59 | * @param {string} hookName
60 | * @param {string} extensionName
61 | * @param {function} func
62 | * @return {void}
63 | */
64 |
65 | this.registerFilter = function(hookName, extensionName, func) {
66 | (this.filters[hookName] = this.filters[hookName] || {})[extensionName] = func;
67 | };
68 | };
--------------------------------------------------------------------------------
/src/base.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * The Base class adds instance methods to all other extensible MixItUp classes,
5 | * enabling the calling of any registered hooks.
6 | *
7 | * @constructor
8 | * @namespace
9 | * @memberof mixitup
10 | * @private
11 | * @since 3.0.0
12 | */
13 |
14 | mixitup.Base = function() {};
15 |
16 | mixitup.Base.prototype = {
17 | constructor: mixitup.Base,
18 |
19 | /**
20 | * Calls any registered hooks for the provided action.
21 | *
22 | * @memberof mixitup.Base
23 | * @private
24 | * @instance
25 | * @since 2.0.0
26 | * @param {string} actionName
27 | * @param {Array<*>} args
28 | * @return {void}
29 | */
30 |
31 | callActions: function(actionName, args) {
32 | var self = this,
33 | hooks = self.constructor.actions[actionName],
34 | extensionName = '';
35 |
36 | if (!hooks || h.isEmptyObject(hooks)) return;
37 |
38 | for (extensionName in hooks) {
39 | hooks[extensionName].apply(self, args);
40 | }
41 | },
42 |
43 | /**
44 | * Calls any registered hooks for the provided filter.
45 | *
46 | * @memberof mixitup.Base
47 | * @private
48 | * @instance
49 | * @since 2.0.0
50 | * @param {string} filterName
51 | * @param {*} input
52 | * @param {Array<*>} args
53 | * @return {*}
54 | */
55 |
56 | callFilters: function(filterName, input, args) {
57 | var self = this,
58 | hooks = self.constructor.filters[filterName],
59 | output = input,
60 | extensionName = '';
61 |
62 | if (!hooks || h.isEmptyObject(hooks)) return output;
63 |
64 | args = args || [];
65 |
66 | for (extensionName in hooks) {
67 | args = h.arrayFromList(args);
68 |
69 | args.unshift(output);
70 |
71 | output = hooks[extensionName].apply(self, args);
72 | }
73 |
74 | return output;
75 | }
76 | };
--------------------------------------------------------------------------------
/demos/sorting-by-multiple-attributes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Sorting by Multiple Attributes
10 |
11 |
12 |
13 | Desc
14 | Asc
15 |
16 |
17 |
18 |
Oscar
19 |
Charlie
20 |
Lima
21 |
Alpha
22 |
Mike
23 |
Zulu
24 |
Tango
25 |
Sierra
26 |
Bravo
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
44 |
45 |
--------------------------------------------------------------------------------
/demos/multiple-instances-global-control-scoping/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Multiple Mixers with Global Control Scoping
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 | None
18 |
19 | Asc
20 | Desc
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 |
52 |
53 |
--------------------------------------------------------------------------------
/tests/unit/mixer-change-layout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 | chai.use(require('chai-as-promised'));
11 |
12 | describe('mixitup.Mixer', () => {
13 | let container = dom.getContainer();
14 | let newClass = 'mixitup-container__display-rows';
15 | let mixer = mixitup(container);
16 |
17 | describe('#changeLayout()', () => {
18 | it('should add a new class name to the container', () => {
19 | return mixer.changeLayout(newClass)
20 | .then(state => {
21 | chai.assert.equal(state.activeContainerClassName, newClass);
22 | chai.assert.isOk(container.matches('.' + newClass));
23 | });
24 | });
25 |
26 | it('should remove the class name from the container', () => {
27 | return mixer.changeLayout('')
28 | .then(state => {
29 | chai.assert.equal(state.activeContainerClassName, '');
30 | chai.assert.notOk(container.matches('.' + newClass));
31 | });
32 | });
33 |
34 | it('should accept a callback function which is invoked after filtering', () => {
35 | let promise = new Promise(resolve => mixer.changeLayout(newClass, resolve));
36 |
37 | chai.assert.isFulfilled(promise);
38 |
39 | return promise
40 | .then(state => {
41 | chai.assert.equal(state.activeContainerClassName, newClass);
42 | chai.assert.isOk(container.matches('.' + newClass));
43 | });
44 | });
45 |
46 | it('should accept a boolean allowing toggling off of animation', () => {
47 | return mixer.changeLayout('', false)
48 | .then(state => {
49 | chai.assert.equal(state.activeContainerClassName, '');
50 | chai.assert.notOk(container.matches('.' + newClass));
51 | });
52 | });
53 | });
54 | });
--------------------------------------------------------------------------------
/demos/attribute-selectors/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Querying via Attribute Selectors
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 | None
18 |
19 | Asc
20 | Desc
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
--------------------------------------------------------------------------------
/tests/unit/queue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 | const JSONDataset = require('../mock/dataset');
9 | const dataset = JSONDataset.map(data => new dom.Item(data));
10 |
11 | chai.use(require('chai-shallow-deep-equal'));
12 | chai.use(require('chai-as-promised'));
13 |
14 | describe('mixitup.Mixer', () => {
15 | describe('Queue', () => {
16 | it('should warn if too many multimix operations are pushed into the queue', () => {
17 | let container = dom.getContainer();
18 | let mixer = mixitup(container, {
19 | debug: {
20 | fauxAsync: true
21 | },
22 | animation: {
23 | duration: 200
24 | }
25 | });
26 |
27 | let promise = Promise.all([
28 | mixer.hide(),
29 | mixer.show(),
30 | mixer.hide(),
31 | mixer.show(),
32 | mixer.hide()
33 | ]);
34 |
35 | chai.assert.isFulfilled(promise);
36 |
37 | return promise;
38 | });
39 |
40 | it('should warn if too many dataset operations are pushed into the queue', () => {
41 | let container = dom.getContainer();
42 |
43 | let mixer = mixitup(container, {
44 | debug: {
45 | fauxAsync: true
46 | },
47 | animation: {
48 | duration: 200
49 | },
50 | data: {
51 | uidKey: 'id'
52 | },
53 | load: {
54 | dataset: dataset
55 | }
56 | });
57 |
58 | let promise = Promise.all([
59 | mixer.dataset([]),
60 | mixer.dataset(dataset),
61 | mixer.dataset([]),
62 | mixer.dataset(dataset),
63 | mixer.dataset([])
64 | ]);
65 |
66 | chai.assert.isFulfilled(promise);
67 |
68 | return promise;
69 | });
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/tests/unit/mixer-get-config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 | chai.use(require('chai-as-promised'));
11 |
12 | describe('mixitup.Mixer', () => {
13 | let container = dom.getContainer();
14 | let mixer = mixitup(container);
15 |
16 | describe('#getConfig()', () => {
17 | it('should retrieve the whole config object if no stringKey passed', () => {
18 | let config = mixer.getConfig();
19 |
20 | chai.assert.instanceOf(config, mixitup.Config);
21 | });
22 |
23 | it('should retrieve a config sub-object if single prop stringKey passed', () => {
24 | let config = mixer.getConfig('animation');
25 |
26 | chai.assert.instanceOf(config, mixitup.ConfigAnimation);
27 | });
28 |
29 | it('should retrieve a nested property value if multi-prop stringKey passed', () => {
30 | let config = mixer.getConfig('animation.effects');
31 |
32 | chai.assert.equal(typeof config, 'string');
33 | });
34 |
35 | it('should retrieve a the current configuration, reflective of any changes', () => {
36 | let newEffects = 'fade translateZ(-100px)';
37 |
38 | mixer.configure({
39 | animation: {
40 | effects: newEffects
41 | }
42 | });
43 |
44 | let newConfig = mixer.getConfig('animation.effects');
45 |
46 | chai.assert.equal(newConfig, newEffects);
47 | });
48 |
49 | it('should throw an error if an invalid configuration option is passed', function() {
50 | chai.assert.throws(() => {
51 | mixer.configure({
52 | animations: {}
53 | });
54 | }, TypeError, mixitup.messages.errorConfigInvalidProperty({
55 | erroneous: 'animations',
56 | suggestion: mixitup.messages.errorConfigInvalidPropertySuggestion({
57 | probableMatch: 'animation'
58 | })
59 | }));
60 | });
61 | });
62 | });
--------------------------------------------------------------------------------
/demos/select-dropdowns/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .controls > select {
23 | margin-right: .75rem;
24 | }
25 |
26 | /* Container
27 | ---------------------------------------------------------------------- */
28 |
29 | .container {
30 | padding: 1rem;
31 | text-align: justify;
32 | font-size: 0.1px;
33 | }
34 |
35 | .container:after {
36 | content: '';
37 | display: inline-block;
38 | width: 100%;
39 | }
40 |
41 | /* Target Elements
42 | ---------------------------------------------------------------------- */
43 |
44 | .mix,
45 | .gap {
46 | display: inline-block;
47 | vertical-align: top;
48 | }
49 |
50 | .mix {
51 | background: #fff;
52 | border-top: .5rem solid currentColor;
53 | border-radius: 2px;
54 | margin-bottom: 1rem;
55 | position: relative;
56 | }
57 |
58 | .mix:before {
59 | content: '';
60 | display: inline-block;
61 | padding-top: 56.25%;
62 | }
63 |
64 | .mix.green {
65 | color: #91e6c7;
66 | }
67 |
68 | .mix.pink {
69 | color: #d595aa;
70 | }
71 |
72 | .mix.blue {
73 | color: #5ecdde;
74 | }
75 |
76 | /* Grid Breakpoints
77 | ---------------------------------------------------------------------- */
78 |
79 | /* 2 Columns */
80 |
81 | .mix,
82 | .gap {
83 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
84 | }
85 |
86 | /* 3 Columns */
87 |
88 | @media screen and (min-width: 541px) {
89 | .mix,
90 | .gap {
91 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
92 | }
93 | }
94 |
95 | /* 4 Columns */
96 |
97 | @media screen and (min-width: 961px) {
98 | .mix,
99 | .gap {
100 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
101 | }
102 | }
103 |
104 | /* 5 Columns */
105 |
106 | @media screen and (min-width: 1281px) {
107 | .mix,
108 | .gap {
109 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
110 | }
111 | }
--------------------------------------------------------------------------------
/demos/removal-by-reference/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Removal by Reference
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 | None
18 |
19 | Asc
20 | Desc
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
61 |
62 |
--------------------------------------------------------------------------------
/demos/select-dropdowns/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Select Dropdowns
10 |
11 |
12 |
13 |
14 | All
15 | Green
16 | Blue
17 | Pink
18 |
19 |
20 |
21 | Ascending
22 | Descending
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/config-behavior.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A group of properties relating to the behavior of the Mixer.
5 | *
6 | * @constructor
7 | * @memberof mixitup.Config
8 | * @name behavior
9 | * @namespace
10 | * @public
11 | * @since 3.1.12
12 | */
13 |
14 | mixitup.ConfigBehavior = function() {
15 | mixitup.Base.call(this);
16 |
17 | this.callActions('beforeConstruct');
18 |
19 | /**
20 | * A boolean dictating whether to allow "live" sorting of the mixer.
21 | *
22 | * Because of the expensive nature of sorting, MixItUp makes use of several
23 | * internal optimizations to skip redundant sorting operations, such as when
24 | * the newly requested sort command is the same as the active one. The caveat
25 | * to this optimization is that "live" edits to the value of a target's sorting
26 | * attribute will be ignored when requesting a re-sort by the same attribute.
27 | *
28 | * By setting to `behavior.liveSort` to `true`, the mixer will always re-sort
29 | * regardless of whether or not the sorting attribute and order have changed.
30 | *
31 | * @example Example: Enabling `liveSort` to allow for re-sorting
32 | *
33 | * var mixer = mixitup(containerEl, {
34 | * behavior: {
35 | * liveSort: true
36 | * },
37 | * load: {
38 | * sort: 'edited:desc'
39 | * }
40 | * });
41 | *
42 | * var target = containerEl.children[3];
43 | *
44 | * console.log(target.getAttribute('data-edited')); // '2015-04-24'
45 | *
46 | * target.setAttribute('data-edited', '2017-08-10'); // Update the target's edited date
47 | *
48 | * mixer.sort('edited:desc')
49 | * .then(function(state) {
50 | * // The target is now at the top of the list
51 | *
52 | * console.log(state.targets[0] === target); // true
53 | * });
54 | *
55 | * @name liveSort
56 | * @memberof mixitup.Config.behavior
57 | * @instance
58 | * @type {boolean}
59 | * @default false
60 | */
61 |
62 | this.liveSort = false;
63 |
64 | this.callActions('afterConstruct');
65 |
66 | h.seal(this);
67 | };
68 |
69 | mixitup.BaseStatic.call(mixitup.ConfigBehavior);
70 |
71 | mixitup.ConfigBehavior.prototype = Object.create(mixitup.Base.prototype);
72 |
73 | mixitup.ConfigBehavior.prototype.constructor = mixitup.ConfigBehavior;
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const gulp = require('gulp');
4 | const jshint = require('gulp-jshint');
5 | const stylish = require('jshint-stylish');
6 | const rename = require('gulp-rename');
7 | const jscs = require('gulp-jscs');
8 | const uglify = require('gulp-uglify');
9 | const livereload = require('gulp-livereload');
10 | const exec = require('child_process').exec;
11 |
12 | gulp.task('default', ['watch']);
13 |
14 | gulp.task('watch', () => {
15 | livereload.listen(35730);
16 |
17 | gulp.watch([
18 | './src/*.js',
19 | './src/*.hbs'
20 | ], ['reload-js'])
21 | .on('change', function(e) {
22 | console.log(
23 | '[gulp-watch] file ' +
24 | e.path +
25 | ' was ' +
26 | e.type +
27 | ', building'
28 | );
29 | });
30 | });
31 |
32 | gulp.task('reload-js', ['build-dist'], () => {
33 | return livereload.changed();
34 | });
35 |
36 | gulp.task('prod', ['uglify']);
37 |
38 | gulp.task('uglify', ['build'], () => {
39 | return gulp.src([
40 | './dist/mixitup.js'
41 | ])
42 | .pipe(uglify({
43 | preserveComments: 'license'
44 | }))
45 | .pipe(rename('mixitup.min.js'))
46 | .on('error', e => console.error('[uglify] ' + e.message))
47 | .pipe(gulp.dest('./dist/'))
48 | .pipe(gulp.dest('./demos/'));
49 | });
50 |
51 | gulp.task('build', ['build-dist'], done => {
52 | exec('node node_modules/mixitup-build/docs.js -s mixitup.js', (e, out) => {
53 | if (out) {
54 | console.log(out);
55 | }
56 |
57 | done(e);
58 | });
59 | });
60 |
61 | gulp.task('build-dist', ['lint', 'code-style'], done => {
62 | exec('node node_modules/mixitup-build/dist.js -o mixitup.js', (e, out) => {
63 | if (out) {
64 | console.log(out);
65 | }
66 |
67 | done(e);
68 | });
69 | });
70 |
71 | gulp.task('lint', () => {
72 | return gulp.src([
73 | './src/*.js'
74 | ], {
75 | base: '/'
76 | })
77 | .pipe(jshint('./.jshintrc'))
78 | .pipe(jshint.reporter(stylish))
79 | .pipe(jshint.reporter('fail'));
80 | });
81 |
82 | gulp.task('code-style', () => {
83 | return gulp.src([
84 | './src/*.js'
85 | ], {
86 | base: '/'
87 | })
88 | .pipe(jscs())
89 | .pipe(jscs.reporter());
90 | });
--------------------------------------------------------------------------------
/demos/basic-ie-8/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 16px;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | vertical-align: top;
26 | padding: 10px;
27 | font-size: 15px;
28 | height: 35px;
29 | min-width: 25px;
30 | background: #444;
31 | cursor: pointer;
32 | color: white;
33 | font-weight: 800;
34 | transition: background 150ms;
35 | }
36 |
37 | .control:hover {
38 | background: #3f3f3f;
39 | }
40 |
41 | .control[data-sort*=":desc"]:after {
42 | transform: translateY(-4px) rotate(-135deg);
43 | }
44 |
45 | .mixitup-control-active {
46 | background: #393939;
47 | }
48 |
49 | .control[data-filter="all"] {
50 | background: #fff;
51 | }
52 |
53 | .control[data-filter=".green"] {
54 | background: #91e6c7;
55 | }
56 |
57 | .control[data-filter=".blue"] {
58 | background: #5ecdde;
59 | }
60 |
61 | .control[data-filter=".pink"] {
62 | background: #d595aa;
63 | }
64 |
65 | .control[data-filter="none"] {
66 | background: #2f2f2f;
67 | }
68 |
69 | /* Container
70 | ---------------------------------------------------------------------- */
71 |
72 | .container {
73 | padding: 16px;
74 | text-align: justify;
75 | font-size: 0.1px;
76 | }
77 |
78 | .container:after {
79 | content: '';
80 | display: inline-block;
81 | width: 100%;
82 | }
83 |
84 | /* Target Elements
85 | ---------------------------------------------------------------------- */
86 |
87 | .mix,
88 | .gap {
89 | display: inline-block;
90 | vertical-align: top;
91 | }
92 |
93 | .mix {
94 | background: #fff;
95 | border-top: 8px solid transparent;
96 | border-radius: 2px;
97 | margin-bottom: 1.25%;
98 | position: relative;
99 | }
100 |
101 | .mix:before {
102 | content: '';
103 | display: inline-block;
104 | padding-top: 56.25%;
105 | }
106 |
107 | .mix.green {
108 | border-top-color: #91e6c7;
109 | }
110 |
111 | .mix.pink {
112 | border-top-color: #d595aa;
113 | }
114 |
115 | .mix.blue {
116 | border-top-color: #5ecdde;
117 | }
118 |
119 | .mix,
120 | .gap {
121 | width: 24%;
122 | }
--------------------------------------------------------------------------------
/src/collection.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A jQuery-collection-like wrapper around one or more `mixitup.Mixer` instances
5 | * allowing simultaneous control of said instances similar to the MixItUp 2 API.
6 | *
7 | * @example
8 | * new mixitup.Collection(instances)
9 | *
10 | * @constructor
11 | * @namespace
12 | * @memberof mixitup
13 | * @private
14 | * @since 3.0.0
15 | * @param {mixitup.Mixer[]} instances
16 | */
17 |
18 | mixitup.Collection = function(instances) {
19 | var instance = null,
20 | i = -1;
21 |
22 | this.callActions('beforeConstruct');
23 |
24 | for (i = 0; instance = instances[i]; i++) {
25 | this[i] = instance;
26 | }
27 |
28 | this.length = instances.length;
29 |
30 | this.callActions('afterConstruct');
31 |
32 | h.freeze(this);
33 | };
34 |
35 | mixitup.BaseStatic.call(mixitup.Collection);
36 |
37 | mixitup.Collection.prototype = Object.create(mixitup.Base.prototype);
38 |
39 | h.extend(mixitup.Collection.prototype,
40 | /** @lends mixitup.Collection */
41 | {
42 | constructor: mixitup.Collection,
43 |
44 | /**
45 | * Calls a method on all instances in the collection by passing the method
46 | * name as a string followed by any applicable parameters to be curried into
47 | * to the method.
48 | *
49 | * @example
50 | * .mixitup(methodName[,arg1][,arg2..]);
51 | *
52 | * @example
53 | * var collection = new Collection([mixer1, mixer2]);
54 | *
55 | * return collection.mixitup('filter', '.category-a')
56 | * .then(function(states) {
57 | * state.forEach(function(state) {
58 | * console.log(state.activeFilter.selector); // .category-a
59 | * });
60 | * });
61 | *
62 | * @public
63 | * @instance
64 | * @since 3.0.0
65 | * @param {string} methodName
66 | * @return {Promise>}
67 | */
68 |
69 | mixitup: function(methodName) {
70 | var self = this,
71 | instance = null,
72 | args = Array.prototype.slice.call(arguments),
73 | tasks = [],
74 | i = -1;
75 |
76 | this.callActions('beforeMixitup');
77 |
78 | args.shift();
79 |
80 | for (i = 0; instance = self[i]; i++) {
81 | tasks.push(instance[methodName].apply(instance, args));
82 | }
83 |
84 | return self.callFilters('promiseMixitup', h.all(tasks, mixitup.libraries), arguments);
85 | }
86 | });
--------------------------------------------------------------------------------
/docs/mixitup.Events.md:
--------------------------------------------------------------------------------
1 | # mixitup.Events
2 |
3 | ## Overview
4 |
5 | The `mixitup.Events` class contains all custom events dispatched by MixItUp at various
6 | points within the lifecycle of a mixer operation.
7 |
8 | Each event is analogous to the callback function of the same name defined in
9 | the `callbacks` configuration object, and is triggered immediately before it.
10 |
11 | Events are always triggered from the container element on which MixItUp is instantiated
12 | upon.
13 |
14 | As with any event, registered event handlers receive the event object as a parameter
15 | which includes a `detail` property containting references to the current `state`,
16 | the `mixer` instance, and other event-specific properties described below.
17 |
18 | ### Contents
19 |
20 | - [mixStart](#mixStart)
21 | - [mixBusy](#mixBusy)
22 | - [mixEnd](#mixEnd)
23 | - [mixFail](#mixFail)
24 | - [mixClick](#mixClick)
25 |
26 |
27 | mixStart
28 |
29 |
30 |
31 |
32 | A custom event triggered immediately after any MixItUp operation is requested
33 | and before animations have begun.
34 |
35 | The `mixStart` event also exposes a `futureState` property via the
36 | `event.detail` object, which represents the final state of the mixer once
37 | the requested operation has completed.
38 |
39 |
40 | |Type
41 | |---
42 | |`CustomEvent`
43 |
44 |
45 | mixBusy
46 |
47 |
48 |
49 |
50 | A custom event triggered when a MixItUp operation is requested while another
51 | operation is in progress, and the animation queue is full, or queueing
52 | is disabled.
53 |
54 |
55 | |Type
56 | |---
57 | |`CustomEvent`
58 |
59 |
60 | mixEnd
61 |
62 |
63 |
64 |
65 | A custom event triggered after any MixItUp operation has completed, and the
66 | state has been updated.
67 |
68 |
69 | |Type
70 | |---
71 | |`CustomEvent`
72 |
73 |
74 | mixFail
75 |
76 |
77 |
78 |
79 | A custom event triggered whenever a filter operation "fails", i.e. no targets
80 | could be found matching the requested filter.
81 |
82 |
83 | |Type
84 | |---
85 | |`CustomEvent`
86 |
87 |
88 | mixClick
89 |
90 |
91 |
92 |
93 | A custom event triggered whenever a MixItUp control is clicked, and before its
94 | respective operation is requested.
95 |
96 | This event also exposes an `originalEvent` property via the `event.detail`
97 | object, which holds a reference to the original click event.
98 |
99 |
100 | |Type
101 | |---
102 | |`CustomEvent`
103 |
104 |
105 |
--------------------------------------------------------------------------------
/src/operation.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * `mixitup.Operation` objects contain all data neccessary to describe the full
5 | * lifecycle of any MixItUp operation. They can be used to compute and store an
6 | * operation for use at a later time (e.g. programmatic tweening).
7 | *
8 | * @constructor
9 | * @namespace
10 | * @memberof mixitup
11 | * @private
12 | * @since 3.0.0
13 | */
14 |
15 | mixitup.Operation = function() {
16 | mixitup.Base.call(this);
17 |
18 | this.callActions('beforeConstruct');
19 |
20 | this.id = '';
21 |
22 | this.args = [];
23 | this.command = null;
24 | this.showPosData = [];
25 | this.toHidePosData = [];
26 |
27 | this.startState = null;
28 | this.newState = null;
29 | this.docState = null;
30 |
31 | this.willSort = false;
32 | this.willChangeLayout = false;
33 | this.hasEffect = false;
34 | this.hasFailed = false;
35 |
36 | this.triggerElement = null;
37 |
38 | this.show = [];
39 | this.hide = [];
40 | this.matching = [];
41 | this.toShow = [];
42 | this.toHide = [];
43 | this.toMove = [];
44 | this.toRemove = [];
45 | this.startOrder = [];
46 | this.newOrder = [];
47 | this.startSort = null;
48 | this.newSort = null;
49 | this.startFilter = null;
50 | this.newFilter = null;
51 | this.startDataset = null;
52 | this.newDataset = null;
53 | this.viewportDeltaX = 0;
54 | this.viewportDeltaY = 0;
55 | this.startX = 0;
56 | this.startY = 0;
57 | this.startHeight = 0;
58 | this.startWidth = 0;
59 | this.newX = 0;
60 | this.newY = 0;
61 | this.newHeight = 0;
62 | this.newWidth = 0;
63 | this.startContainerClassName = '';
64 | this.startDisplay = '';
65 | this.newContainerClassName = '';
66 | this.newDisplay = '';
67 |
68 | this.callActions('afterConstruct');
69 |
70 | h.seal(this);
71 | };
72 |
73 | mixitup.BaseStatic.call(mixitup.Operation);
74 |
75 | mixitup.Operation.prototype = Object.create(mixitup.Base.prototype);
76 |
77 | mixitup.Operation.prototype.constructor = mixitup.Operation;
--------------------------------------------------------------------------------
/demos/mock-api.js:
--------------------------------------------------------------------------------
1 | (function(window) {
2 | var Api = function(dataset) {
3 | var _db = [];
4 |
5 | Object.defineProperties(this, {
6 | db: {
7 | get: function() {
8 | return _db.slice();
9 | },
10 | set: function(value) {
11 | if (!Array.isArray(value)) {
12 | throw new TypeError('[mock-api] Dataset must be an array');
13 | }
14 |
15 | if (!value.length) {
16 | throw new TypeError('[mock-api] Dataset must contain one or more elements');
17 | }
18 |
19 | _db = value;
20 | }
21 | }
22 | });
23 |
24 | this.init(dataset);
25 | };
26 |
27 | Api.prototype = {
28 | constructor: Api,
29 |
30 | init: function(dataset) {
31 | this.db = dataset;
32 | },
33 |
34 | get: function(query) {
35 | var self = this;
36 |
37 | return Promise.resolve()
38 | .then(function() {
39 | var output;
40 |
41 | query = Object.assign(new Api.Query(), query);
42 |
43 | Object.freeze(query);
44 |
45 | output = self.filter(self.db, query);
46 |
47 | output = self.sort(output, query);
48 |
49 | return output;
50 | });
51 | },
52 |
53 | filter: function(input, query) {
54 | return input.filter(function(item) {
55 | var key;
56 | var value;
57 |
58 | for (key in query) {
59 | if (key.match(/^\$/g)) continue;
60 |
61 | value = query[key];
62 |
63 | if (value === 'all') return true;
64 |
65 | if (item[key] !== value) return false;
66 | }
67 |
68 | return true;
69 | });
70 | },
71 |
72 | sort: function(input, query) {
73 | return input.sort(function(a, b) {
74 | var valueA = a[query.$sort_by];
75 | var valueB = b[query.$sort_by];
76 |
77 | if (valueA > valueB) {
78 | return query.$order === 'asc' ? 1 : -1;
79 | } else if (valueA < valueB) {
80 | return query.$order === 'asc' ? -1 : 1;
81 | } else {
82 | return 0;
83 | }
84 | });
85 | }
86 | };
87 |
88 | Api.Query = function() {
89 | this.$sort_by = 'id';
90 | this.$order = 'asc';
91 | };
92 |
93 | window.Api = Api;
94 | })(window);
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * `mixitup.Config` is an interface used for customising the functionality of a
5 | * mixer instance. It is organised into several semantically distinct sub-objects,
6 | * each one pertaining to a particular aspect of MixItUp functionality.
7 | *
8 | * An object literal containing any or all of the available properies,
9 | * known as the "configuration object", can be passed as the second parameter to
10 | * the `mixitup` factory function when creating a mixer instance to customise its
11 | * functionality as needed.
12 | *
13 | * If no configuration object is passed, the mixer instance will take on the default
14 | * configuration values detailed below.
15 | *
16 | * @example Example 1: Creating and passing the configuration object
17 | * // Create a configuration object with desired values
18 | *
19 | * var config = {
20 | * animation: {
21 | * enable: false
22 | * },
23 | * selectors: {
24 | * target: '.item'
25 | * }
26 | * };
27 | *
28 | * // Pass the configuration object to the mixitup factory function
29 | *
30 | * var mixer = mixitup(containerEl, config);
31 | *
32 | * @example Example 2: Passing the configuration object inline
33 | * // Typically, the configuration object is passed inline for brevity.
34 | *
35 | * var mixer = mixitup(containerEl, {
36 | * controls: {
37 | * live: true,
38 | * toggleLogic: 'and'
39 | * }
40 | * });
41 | *
42 | *
43 | * @constructor
44 | * @memberof mixitup
45 | * @namespace
46 | * @public
47 | * @since 2.0.0
48 | */
49 |
50 | mixitup.Config = function() {
51 | mixitup.Base.call(this);
52 |
53 | this.callActions('beforeConstruct');
54 |
55 | this.animation = new mixitup.ConfigAnimation();
56 | this.behavior = new mixitup.ConfigBehavior();
57 | this.callbacks = new mixitup.ConfigCallbacks();
58 | this.controls = new mixitup.ConfigControls();
59 | this.classNames = new mixitup.ConfigClassNames();
60 | this.data = new mixitup.ConfigData();
61 | this.debug = new mixitup.ConfigDebug();
62 | this.layout = new mixitup.ConfigLayout();
63 | this.load = new mixitup.ConfigLoad();
64 | this.selectors = new mixitup.ConfigSelectors();
65 | this.render = new mixitup.ConfigRender();
66 | this.templates = new mixitup.ConfigTemplates();
67 |
68 | this.callActions('afterConstruct');
69 |
70 | h.seal(this);
71 | };
72 |
73 | mixitup.BaseStatic.call(mixitup.Config);
74 |
75 | mixitup.Config.prototype = Object.create(mixitup.Base.prototype);
76 |
77 | mixitup.Config.prototype.constructor = mixitup.Config;
--------------------------------------------------------------------------------
/demos/grid-flex-box-matching-heights/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Flex-box Grid with Matching Heights
10 |
11 |
12 |
13 | Shuffle
14 |
15 |
16 |
17 |
18 |
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore. Quis autem vel eum iure reprehenderit qui in ea voluptate velit similique sunt in culpa qui officia deserunt mollitia animi.
19 |
20 |
21 |
22 |
Similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum.
23 |
24 |
25 |
26 |
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias.
27 |
28 |
29 |
30 |
Similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum.
31 |
32 |
33 |
34 |
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias.
35 |
36 |
37 |
38 |
Similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum.
39 |
40 |
41 |
42 |
Magni dolores eos qui ratione voluptatem sequi nesciun.
43 |
44 |
45 |
46 |
Similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum.
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
65 |
66 |
--------------------------------------------------------------------------------
/demos/loading-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Basic
10 |
11 |
12 |
13 | All
14 | Green
15 | Blue
16 | Pink
17 | None
18 |
19 | Asc
20 | Desc
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
70 |
71 |
--------------------------------------------------------------------------------
/tests/functional/styles.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, u, i, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video {
14 | margin: 0;
15 | padding: 0;
16 | border: 0;
17 | font-size: 100%;
18 | font: inherit;
19 | vertical-align: baseline;
20 | }
21 | /* HTML5 display-role reset for older browsers */
22 | article, aside, details, figcaption, figure,
23 | footer, header, hgroup, menu, nav, section {
24 | display: block;
25 | }
26 | body {
27 | line-height: 1;
28 | }
29 | ol, ul {
30 | list-style: none;
31 | }
32 | blockquote, q {
33 | quotes: none;
34 | }
35 | blockquote:before, blockquote:after,
36 | q:before, q:after {
37 | content: '';
38 | content: none;
39 | }
40 | table {
41 | border-collapse: collapse;
42 | border-spacing: 0;
43 | }
44 |
45 | body {
46 | background: #eee;
47 | }
48 |
49 | .mixitup-control,
50 | .mixitup-pager {
51 | cursor: pointer;
52 | display: inline-block;
53 | padding: .5rem;
54 | background: #eee;
55 | }
56 |
57 | .mixitup-control-active,
58 | .mixitup-pager-active {
59 | font-weight: bold;
60 | }
61 |
62 | .mixitup-pager-disabled {
63 | opacity: .8;
64 | }
65 |
66 | .mix {
67 | vertical-align: top;
68 | background: skyblue;
69 | border-radius: 5px;
70 | margin: 2rem;
71 | color: transparent;
72 |
73 | transition: opacity 300ms;
74 |
75 | -webkit-user-select: none;
76 | }
77 |
78 | .mix,
79 | .gap {
80 | display: inline-block;
81 | width: 6%;
82 | margin: 0 2rem;
83 | }
84 |
85 | .mix {
86 | margin: 2rem;
87 | }
88 |
89 | .mix:before {
90 | content: '';
91 | display: inline-block;
92 | padding-top: 100%;
93 | }
94 |
95 | .mixitup-target-placeholder {
96 | background: transparent !important;
97 | border: 2px dashed #ccc;
98 | box-sizing: border-box;
99 | }
100 |
101 | .mixitup-target-dragging {
102 | opacity: .5;
103 | }
104 |
105 | .mixitup-target-closest {
106 | border: 3px solid orange;
107 | }
108 |
109 | .sandbox {
110 | overflow: hidden;
111 | text-align: justify;
112 | background: #333;
113 | min-height: 2rem;
114 | }
115 |
116 | .sandbox:after {
117 | content: '';
118 | width: 100%;
119 | display: inline-block;
120 | }
121 |
122 | .sandbox__mixitup .mix {
123 |
124 | }
125 |
126 | .mix.cat-2 {
127 | background: violet;
128 | }
129 |
130 | .mix.cat-3 {
131 | background: yellow;
132 | }
133 |
134 | .mix.cat-4 {
135 | background: aquamarine;
136 | }
--------------------------------------------------------------------------------
/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "requireCurlyBraces": [
3 | "else",
4 | "for",
5 | "while",
6 | "do",
7 | "try",
8 | "catch"
9 | ],
10 | "requireSpaceAfterKeywords": [
11 | "if",
12 | "else",
13 | "for",
14 | "while",
15 | "do",
16 | "case",
17 | "return",
18 | "try",
19 | "typeof"
20 | ],
21 | "safeContextKeyword": ["self"],
22 | "maximumLineLength": {
23 | "value": 140,
24 | "allowComments": true,
25 | "allowRegex": true
26 | },
27 | "requireSpaceBeforeBlockStatements": true,
28 | "requireParenthesesAroundIIFE": true,
29 | "requireSpaceAfterLineComment": {
30 | "allExcept": ["#", "="]
31 | },
32 | "requireSpacesInConditionalExpression": true,
33 | "disallowSpacesInNamedFunctionExpression": {
34 | "beforeOpeningRoundBrace": true
35 | },
36 | "disallowSpacesInFunctionDeclaration": {
37 | "beforeOpeningRoundBrace": true
38 | },
39 | "disallowFunctionDeclarations": false,
40 | "requireSpaceBetweenArguments": true,
41 | "requireMultipleVarDecl": false,
42 | "requireBlocksOnNewline": true,
43 | "requireSemicolons": true,
44 | "disallowEmptyBlocks": true,
45 | "disallowSpacesInsideArrayBrackets": true,
46 | "disallowSpacesInsideParentheses": true,
47 | "requireCommaBeforeLineBreak": true,
48 | "requireLineBreakAfterVariableAssignment": true,
49 | "requirePaddingNewlinesBeforeKeywords": [
50 | "do",
51 | "for",
52 | "if",
53 | "switch",
54 | "try",
55 | "void",
56 | "while",
57 | "return"
58 | ],
59 | "requirePaddingNewLinesInObjects": true,
60 | "disallowSpaceAfterPrefixUnaryOperators": true,
61 | "disallowSpaceBeforePostfixUnaryOperators": true,
62 | "disallowSpaceBeforeBinaryOperators": [
63 | ","
64 | ],
65 | "requireSpacesInForStatement": true,
66 | "requireSpaceBeforeBinaryOperators": true,
67 | "requireSpaceAfterBinaryOperators": true,
68 | "disallowKeywords": [
69 | "with"
70 | ],
71 | "validateIndentation": 4,
72 | "disallowMixedSpacesAndTabs": true,
73 | "disallowTrailingWhitespace": true,
74 | "disallowTrailingComma": true,
75 | "disallowKeywordsOnNewLine": [
76 | "else"
77 | ],
78 | "requireCapitalizedConstructors": true,
79 | "disallowNewlineBeforeBlockStatements": true,
80 | "disallowMultipleLineStrings": true,
81 | "disallowMultipleLineBreaks": true,
82 | "requireSpaceBeforeObjectValues": true,
83 | "validateQuoteMarks": "'",
84 | "jsDoc": {
85 | "checkAnnotations": true,
86 | "requireParamTypes": true,
87 | "checkParamNames": true,
88 | "checkParamExistence": true,
89 | // "checkRedundantParams": true,
90 | "checkReturnTypes": true,
91 | "requireNewlineAfterDescription": true,
92 | // "requireParamDescription": true,
93 | "requireDescriptionCompleteSentence": true
94 | }
95 | }
--------------------------------------------------------------------------------
/tests/unit/controls-sort.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 | chai.use(require('chai-as-promised'));
11 |
12 | describe('Controls', () => {
13 | describe('Sort', () => {
14 | let frag = document.createDocumentFragment();
15 | let container = dom.getContainer();
16 | let controls = dom.getSortControls();
17 |
18 | container.insertBefore(controls, container.children[0]);
19 |
20 | frag.appendChild(container);
21 |
22 | let mixer = mixitup(container, {
23 | controls: {
24 | scope: 'local'
25 | }
26 | }, frag);
27 |
28 | after(() => mixer.destroy());
29 |
30 | it('should detect nested sort controls and set active states upon instantiation', () => {
31 | let control1 = controls.querySelector('[data-sort="default"]');
32 | let control2 = controls.querySelector('[data-sort="default:asc"]');
33 |
34 | chai.assert.isOk(control1.matches('.mixitup-control-active'));
35 | chai.assert.isOk(control2.matches('.mixitup-control-active'));
36 | });
37 |
38 | it('should handle sort control clicks with a single sortString value', () => {
39 | let control = controls.querySelector('[data-sort="default:desc"]');
40 |
41 | control.click();
42 |
43 | let state = mixer.getState();
44 |
45 | chai.assert.isOk(control.matches('.mixitup-control-active'));
46 | chai.assert.equal(state.activeSort.sortString, 'default:desc');
47 | chai.assert.equal(state.activeSort.attribute, '');
48 | chai.assert.equal(state.activeSort.order, 'desc');
49 | });
50 |
51 | it('should handle sort control clicks with "random" value', () => {
52 | let control = controls.querySelector('[data-sort="random"]');
53 |
54 | control.click();
55 |
56 | let state = mixer.getState();
57 |
58 | chai.assert.isOk(control.matches('.mixitup-control-active'));
59 | chai.assert.equal(state.activeSort.sortString, 'random');
60 | chai.assert.equal(state.activeSort.attribute, '');
61 | chai.assert.equal(state.activeSort.order, 'random');
62 | });
63 |
64 | it('should activate buttons in response to matching API calls', () => {
65 | let control = controls.querySelector('[data-sort="published:asc views:desc"]');
66 |
67 | return mixer.sort('published:asc views:desc')
68 | .then(state => {
69 | chai.assert.isOk(control.matches('.mixitup-control-active'));
70 | chai.assert.equal(state.activeSort.sortString, 'published:asc');
71 | chai.assert.isOk(state.activeSort.next);
72 | chai.assert.equal(state.activeSort.next.sortString, 'views:desc');
73 | });
74 | });
75 | });
76 | });
--------------------------------------------------------------------------------
/src/config-selectors.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A group of properties defining the selectors used to query elements within a mixitup container.
5 | *
6 | * @constructor
7 | * @memberof mixitup.Config
8 | * @name selectors
9 | * @namespace
10 | * @public
11 | * @since 3.0.0
12 | */
13 |
14 | mixitup.ConfigSelectors = function() {
15 | mixitup.Base.call(this);
16 |
17 | this.callActions('beforeConstruct');
18 |
19 | /**
20 | * A selector string used to query and index target elements within the container.
21 | *
22 | * By default, the class selector `'.mix'` is used, but this can be changed to an
23 | * attribute or element selector to match the style of your project.
24 | *
25 | * @example Example 1: Changing the target selector
26 | *
27 | * var mixer = mixitup(containerEl, {
28 | * selectors: {
29 | * target: '.portfolio-item'
30 | * }
31 | * });
32 | *
33 | * @example Example 2: Using an attribute selector as a target selector
34 | *
35 | * // The mixer will search for any children with the attribute `data-ref="mix"`
36 | *
37 | * var mixer = mixitup(containerEl, {
38 | * selectors: {
39 | * target: '[data-ref="mix"]'
40 | * }
41 | * });
42 | *
43 | * @name target
44 | * @memberof mixitup.Config.selectors
45 | * @instance
46 | * @type {string}
47 | * @default '.mix'
48 | */
49 |
50 | this.target = '.mix';
51 |
52 | /**
53 | * A optional selector string used to add further specificity to the querying of control elements,
54 | * in addition to their mandatory data attribute (e.g. `data-filter`, `data-toggle`, `data-sort`).
55 | *
56 | * This can be used if other elements in your document must contain the above attributes
57 | * (e.g. for use in third-party scripts), and would otherwise interfere with MixItUp. Adding
58 | * an additional `control` selector of your choice allows MixItUp to restrict event handling
59 | * to only those elements matching the defined selector.
60 | *
61 | * @name control
62 | * @memberof mixitup.Config.selectors
63 | * @instance
64 | * @type {string}
65 | * @default ''
66 | *
67 | * @example Example 1: Adding a `selectors.control` selector
68 | *
69 | * var mixer = mixitup(containerEl, {
70 | * selectors: {
71 | * control: '.mixitup-control'
72 | * }
73 | * });
74 | *
75 | * // Will not be handled:
76 | * //
77 | *
78 | * // Will be handled:
79 | * //
80 | */
81 |
82 | this.control = '';
83 |
84 | this.callActions('afterConstruct');
85 |
86 | h.seal(this);
87 | };
88 |
89 | mixitup.BaseStatic.call(mixitup.ConfigSelectors);
90 |
91 | mixitup.ConfigSelectors.prototype = Object.create(mixitup.Base.prototype);
92 |
93 | mixitup.ConfigSelectors.prototype.constructor = mixitup.ConfigSelectors;
--------------------------------------------------------------------------------
/demos/sorting-by-default/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-sort]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | border-top: 2px solid;
44 | border-left: 2px solid;
45 | top: calc(50% - 6px);
46 | left: calc(50% - 6px);
47 | transform: translateY(1px) rotate(45deg);
48 | }
49 |
50 | .control[data-sort*=":desc"]:after {
51 | transform: translateY(-4px) rotate(-135deg);
52 | }
53 |
54 | .mixitup-control-active {
55 | background: #393939;
56 | }
57 |
58 | .mixitup-control-active[data-filter]:after {
59 | background: transparent;
60 | }
61 |
62 | .control:first-of-type {
63 | border-radius: 3px 0 0 3px;
64 | }
65 |
66 | .control:last-of-type {
67 | border-radius: 0 3px 3px 0;
68 | }
69 |
70 | /* Container
71 | ---------------------------------------------------------------------- */
72 |
73 | .container {
74 | padding: 1rem;
75 | text-align: justify;
76 | font-size: 0.1px;
77 | }
78 |
79 | .container:after {
80 | content: '';
81 | display: inline-block;
82 | width: 100%;
83 | }
84 |
85 | /* Target Elements
86 | ---------------------------------------------------------------------- */
87 |
88 | .mix,
89 | .gap {
90 | display: inline-block;
91 | vertical-align: top;
92 | }
93 |
94 | .mix {
95 | background: #fff;
96 | border-radius: 2px;
97 | margin-bottom: 1rem;
98 | position: relative;
99 | font-family: 'helvetica-neue', arial, sans-serif;
100 | }
101 |
102 | .mix:before {
103 | content: '';
104 | display: inline-block;
105 | padding-top: 56.25%;
106 | }
107 |
108 | /* Grid Breakpoints
109 | ---------------------------------------------------------------------- */
110 |
111 | /* 2 Columns */
112 |
113 | .mix,
114 | .gap {
115 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
116 | }
117 |
118 | /* 3 Columns */
119 |
120 | @media screen and (min-width: 541px) {
121 | .mix,
122 | .gap {
123 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
124 | }
125 | }
126 |
127 | /* 4 Columns */
128 |
129 | @media screen and (min-width: 961px) {
130 | .mix,
131 | .gap {
132 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
133 | }
134 | }
135 |
136 | /* 5 Columns */
137 |
138 | @media screen and (min-width: 1281px) {
139 | .mix,
140 | .gap {
141 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
142 | }
143 | }
144 |
145 |
146 |
--------------------------------------------------------------------------------
/demos/grid-flex-box-matching-heights/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 |
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: antialiased;
8 | }
9 |
10 | *,
11 | *:before,
12 | *:after {
13 | box-sizing: border-box;
14 | }
15 |
16 | /* Controls
17 | ---------------------------------------------------------------------- */
18 |
19 | .controls {
20 | padding: 1rem;
21 | background: #333;
22 | font-size: 0.1px;
23 | }
24 |
25 | .control {
26 | position: relative;
27 | display: inline-block;
28 | padding: .5rem;
29 | background: #444;
30 | cursor: pointer;
31 | font-size: .9rem;
32 | font-weight: 800;
33 | color: white;
34 | transition: background 150ms;
35 | }
36 |
37 | .control:hover {
38 | background: #3f3f3f;
39 | }
40 |
41 | .mixitup-control-active {
42 | background: #393939;
43 | }
44 |
45 | .control:first-of-type {
46 | border-radius: 3px 0 0 3px;
47 | }
48 |
49 | .control:last-of-type {
50 | border-radius: 0 3px 3px 0;
51 | }
52 |
53 | /* Container
54 | ---------------------------------------------------------------------- */
55 |
56 | .container {
57 | padding: 1rem;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: wrap;
61 | align-content: flex-start;
62 | justify-content: space-between;
63 | }
64 |
65 | /* Target Elements
66 | ---------------------------------------------------------------------- */
67 |
68 | .mix,
69 | .gap {
70 | display: inline-flex;
71 | vertical-align: top;
72 | }
73 |
74 | .mix {
75 | background: #fff;
76 | border-top: .5rem solid currentColor;
77 | border-radius: 2px;
78 | margin-bottom: 1rem;
79 | position: relative;
80 | color: transparent;
81 | font-family: 'helvetica-neue', arial, sans-serif;
82 | }
83 |
84 | .mix:before {
85 | content: '';
86 | display: inline-block;
87 | padding-top: 56.25%;
88 | }
89 |
90 | .mix.green {
91 | color: #91e6c7;
92 | }
93 |
94 | .mix.pink {
95 | color: #d595aa;
96 | }
97 |
98 | .mix.blue {
99 | color: #5ecdde;
100 | }
101 |
102 | .mix p {
103 | padding: 1rem;
104 | display: inline-block;
105 | font-size: calc(1vw + .5rem);
106 | color: #333;
107 | line-height: 1.4;
108 | font-weight: 300;
109 | }
110 |
111 | /* Grid Breakpoints
112 | ---------------------------------------------------------------------- */
113 |
114 | /* 2 Columns */
115 |
116 | .mix,
117 | .gap {
118 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
119 | }
120 |
121 | /* 3 Columns */
122 |
123 | @media screen and (min-width: 541px) {
124 | .mix,
125 | .gap {
126 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
127 | }
128 | }
129 |
130 | /* 4 Columns */
131 |
132 | @media screen and (min-width: 961px) {
133 | .mix,
134 | .gap {
135 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
136 | }
137 | }
138 |
139 | /* 5 Columns */
140 |
141 | @media screen and (min-width: 1281px) {
142 | .mix,
143 | .gap {
144 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
145 | }
146 | }
147 |
148 |
149 |
--------------------------------------------------------------------------------
/demos/multiple-instances-local-control-scoping/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Multiple Mixers with Local Control Scoping
10 |
11 |
12 |
13 |
14 | All
15 | Green
16 | Blue
17 | Pink
18 | None
19 |
20 | Asc
21 | Desc
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | All
38 | Green
39 | Blue
40 | Pink
41 | None
42 |
43 | Asc
44 | Desc
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
73 |
74 |
--------------------------------------------------------------------------------
/src/config-debug.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A group of properties allowing the toggling of various debug features.
5 | *
6 | * @constructor
7 | * @memberof mixitup.Config
8 | * @name debug
9 | * @namespace
10 | * @public
11 | * @since 3.0.0
12 | */
13 |
14 | mixitup.ConfigDebug = function() {
15 | mixitup.Base.call(this);
16 |
17 | this.callActions('beforeConstruct');
18 |
19 | /**
20 | * A boolean dictating whether or not the mixer instance returned by the
21 | * `mixitup()` factory function should expose private properties and methods.
22 | *
23 | * By default, mixer instances only expose their public API, but enabling
24 | * debug mode will give you access to various mixer internals which may aid
25 | * in debugging, or the authoring of extensions.
26 | *
27 | * @example Example: Enabling debug mode
28 | *
29 | * var mixer = mixitup(containerEl, {
30 | * debug: {
31 | * enable: true
32 | * }
33 | * });
34 | *
35 | * // Private properties and methods will now be visible on the mixer instance:
36 | *
37 | * console.log(mixer);
38 | *
39 | * @name enable
40 | * @memberof mixitup.Config.debug
41 | * @instance
42 | * @type {boolean}
43 | * @default false
44 | */
45 |
46 | this.enable = false;
47 |
48 | /**
49 | * A boolean dictating whether or not warnings should be shown when various
50 | * common gotchas occur.
51 | *
52 | * Warnings are intended to provide insights during development when something
53 | * occurs that is not a fatal, but may indicate an issue with your integration,
54 | * and are therefore turned on by default. However, you may wish to disable
55 | * them in production.
56 | *
57 | * @example Example 1: Disabling warnings
58 | *
59 | * var mixer = mixitup(containerEl, {
60 | * debug: {
61 | * showWarnings: false
62 | * }
63 | * });
64 | *
65 | * @example Example 2: Disabling warnings based on environment
66 | *
67 | * var showWarnings = myAppConfig.environment === 'development' ? true : false;
68 | *
69 | * var mixer = mixitup(containerEl, {
70 | * debug: {
71 | * showWarnings: showWarnings
72 | * }
73 | * });
74 | *
75 | * @name showWarnings
76 | * @memberof mixitup.Config.debug
77 | * @instance
78 | * @type {boolean}
79 | * @default true
80 | */
81 |
82 | this.showWarnings = true;
83 |
84 | /**
85 | * Used for server-side testing only.
86 | *
87 | * @private
88 | * @name fauxAsync
89 | * @memberof mixitup.Config.debug
90 | * @instance
91 | * @type {boolean}
92 | * @default false
93 | */
94 |
95 | this.fauxAsync = false;
96 |
97 | this.callActions('afterConstruct');
98 |
99 | h.seal(this);
100 | };
101 |
102 | mixitup.BaseStatic.call(mixitup.ConfigDebug);
103 |
104 | mixitup.ConfigDebug.prototype = Object.create(mixitup.Base.prototype);
105 |
106 | mixitup.ConfigDebug.prototype.constructor = mixitup.ConfigDebug;
--------------------------------------------------------------------------------
/demos/checkboxes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Checkboxes
10 |
11 |
12 |
13 |
29 |
30 |
Asc
31 |
Desc
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
85 |
86 |
--------------------------------------------------------------------------------
/src/config-render.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A group of optional render functions for creating and updating elements.
5 | *
6 | * All render functions receive a data object, and should return a valid HTML string.
7 | *
8 | * @constructor
9 | * @memberof mixitup.Config
10 | * @name render
11 | * @namespace
12 | * @public
13 | * @since 3.0.0
14 | */
15 |
16 | mixitup.ConfigRender = function() {
17 | mixitup.Base.call(this);
18 |
19 | this.callActions('beforeConstruct');
20 |
21 | /**
22 | * A function returning an HTML string representing a target element, or a reference to a
23 | * single DOM element.
24 | *
25 | * The function is invoked as part of the `.dataset()` API, whenever a new item is added
26 | * to the dataset, or an item in the dataset changes (if `dataset.dirtyCheck` is enabled).
27 | *
28 | * The function receives the relevant dataset item as its first parameter.
29 | *
30 | * @example Example 1: Using string concatenation
31 | *
32 | * var mixer = mixitup(containerEl, {
33 | * render: {
34 | * target: function(item) {
35 | * return (
36 | * '<div class="mix">' +
37 | * '<h2>' + item.title + '</h2>' +
38 | * '</div>'
39 | * );
40 | * }
41 | * }
42 | * });
43 | *
44 | * @example Example 2: Using an ES2015 template literal
45 | *
46 | * var mixer = mixitup(containerEl, {
47 | * render: {
48 | * target: function(item) {
49 | * return (
50 | * `<div class="mix">
51 | * <h2>${item.title}</h2>
52 | * </div>`
53 | * );
54 | * }
55 | * }
56 | * });
57 | *
58 | * @example Example 3: Using a Handlebars template
59 | * {{{{raw}}}}
60 | * var targetTemplate = Handlebars.compile('<div class="mix"><h2>{{title}}</h2></div>');
61 | * {{{{/raw}}}}
62 | * var mixer = mixitup(containerEl, {
63 | * render: {
64 | * target: targetTemplate
65 | * }
66 | * });
67 | *
68 | * @example Example 4: Returning a DOM element
69 | *
70 | * var mixer = mixitup(containerEl, {
71 | * render: {
72 | * target: function(item) {
73 | * // Create a single element using your framework's built-in renderer
74 | *
75 | * var el = ...
76 | *
77 | * return el;
78 | * }
79 | * }
80 | * });
81 | *
82 | * @name target
83 | * @memberof mixitup.Config.render
84 | * @instance
85 | * @type {function}
86 | * @default 'null'
87 | */
88 |
89 | this.target = null;
90 |
91 | this.callActions('afterConstruct');
92 |
93 | h.seal(this);
94 | };
95 |
96 | mixitup.BaseStatic.call(mixitup.ConfigRender);
97 |
98 | mixitup.ConfigRender.prototype = Object.create(mixitup.Base.prototype);
99 |
100 | mixitup.ConfigRender.prototype.constructor = mixitup.ConfigRender;
--------------------------------------------------------------------------------
/tests/unit/mixer-toggle-on-off.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | require('jsdom-global')();
5 |
6 | const chai = require('chai');
7 | const dom = require('../mock/dom');
8 | const mixitup = require('../../dist/mixitup.js');
9 |
10 | chai.use(require('chai-shallow-deep-equal'));
11 | chai.use(require('chai-as-promised'));
12 |
13 | describe('mixitup.Mixer', () => {
14 | describe('#toggleOn()', () => {
15 | const container = dom.getContainer();
16 | const mixer = mixitup(container);
17 |
18 | it('should activate an initial toggle', () => {
19 | const matching = Array.prototype.slice.call(container.querySelectorAll('.category-a'));
20 |
21 | return mixer.toggleOn('.category-a')
22 | .then(state => {
23 | chai.assert.equal(state.totalShow, matching.length);
24 | chai.assert.deepEqual(state.show, matching);
25 | chai.assert.deepEqual(state.matching, matching);
26 | });
27 | });
28 |
29 | it('should activate a further toggle', () => {
30 | const matching = Array.prototype.slice.call(container.querySelectorAll('.category-a, .category-c'));
31 |
32 | return mixer.toggleOn('.category-c')
33 | .then(state => {
34 | chai.assert.equal(state.totalShow, matching.length);
35 | chai.assert.deepEqual(state.show, matching);
36 | chai.assert.deepEqual(state.matching, matching);
37 | });
38 | });
39 |
40 | it('should activate a non-existant toggle with no effect', () => {
41 | const matching = Array.prototype.slice.call(container.querySelectorAll('.category-a, .category-c'));
42 |
43 | return mixer.toggleOn('.category-z')
44 | .then(state => {
45 | chai.assert.equal(state.totalShow, matching.length);
46 | chai.assert.deepEqual(state.show, matching);
47 | chai.assert.deepEqual(state.matching, matching);
48 | });
49 | });
50 | });
51 |
52 | describe('#toggleOff()', () => {
53 | const container = dom.getContainer();
54 | const mixer = mixitup(container, {
55 | load: {
56 | filter: '.category-a, .category-b, .category-c'
57 | }
58 | });
59 |
60 | it('should deactivate a toggle', () => {
61 | const matching = Array.prototype.slice.call(container.querySelectorAll('.category-a, .category-b'));
62 |
63 | return mixer.toggleOff('.category-c')
64 | .then(state => {
65 | chai.assert.equal(state.totalShow, matching.length);
66 | chai.assert.deepEqual(state.show, matching);
67 | chai.assert.deepEqual(state.matching, matching);
68 | });
69 | });
70 |
71 | it('should deactivate a non existent toggle with no effect', () => {
72 | const matching = Array.prototype.slice.call(container.querySelectorAll('.category-a, .category-b'));
73 |
74 | return mixer.toggleOff('.category-z')
75 | .then(state => {
76 | chai.assert.equal(state.totalShow, matching.length);
77 | chai.assert.deepEqual(state.show, matching);
78 | chai.assert.deepEqual(state.matching, matching);
79 | });
80 | });
81 | });
82 | });
83 |
--------------------------------------------------------------------------------
/demos/sorting-by-attribute/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-sort]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | border-top: 2px solid;
44 | border-left: 2px solid;
45 | top: calc(50% - 6px);
46 | left: calc(50% - 6px);
47 | transform: translateY(1px) rotate(45deg);
48 | }
49 |
50 | .control[data-sort*=":desc"]:after {
51 | transform: translateY(-4px) rotate(-135deg);
52 | }
53 |
54 | .mixitup-control-active {
55 | background: #393939;
56 | }
57 |
58 | .mixitup-control-active[data-filter]:after {
59 | background: transparent;
60 | }
61 |
62 | .control:first-of-type {
63 | border-radius: 3px 0 0 3px;
64 | }
65 |
66 | .control:last-of-type {
67 | border-radius: 0 3px 3px 0;
68 | }
69 |
70 | /* Container
71 | ---------------------------------------------------------------------- */
72 |
73 | .container {
74 | padding: 1rem;
75 | text-align: justify;
76 | font-size: 0.1px;
77 | }
78 |
79 | .container:after {
80 | content: '';
81 | display: inline-block;
82 | width: 100%;
83 | }
84 |
85 | /* Target Elements
86 | ---------------------------------------------------------------------- */
87 |
88 | .mix,
89 | .gap {
90 | display: inline-block;
91 | vertical-align: top;
92 | }
93 |
94 | .mix {
95 | background: #fff;
96 | border-radius: 2px;
97 | margin-bottom: 1rem;
98 | position: relative;
99 | font-family: 'helvetica-neue', arial, sans-serif;
100 | }
101 |
102 | .mix:before {
103 | content: '';
104 | display: inline-block;
105 | padding-top: 56.25%;
106 | }
107 |
108 | .mix[data-published-date]:after {
109 | position: absolute;
110 | content: attr(data-published-date);
111 | font-size: 1rem;
112 | font-weight: bold;
113 | color: #aaa;
114 | padding: 1rem;
115 | width: 100%;
116 | top: 0;
117 | left: 0;
118 | }
119 |
120 | /* Grid Breakpoints
121 | ---------------------------------------------------------------------- */
122 |
123 | /* 2 Columns */
124 |
125 | .mix,
126 | .gap {
127 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
128 | }
129 |
130 | /* 3 Columns */
131 |
132 | @media screen and (min-width: 541px) {
133 | .mix,
134 | .gap {
135 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
136 | }
137 | }
138 |
139 | /* 4 Columns */
140 |
141 | @media screen and (min-width: 961px) {
142 | .mix,
143 | .gap {
144 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
145 | }
146 | }
147 |
148 | /* 5 Columns */
149 |
150 | @media screen and (min-width: 1281px) {
151 | .mix,
152 | .gap {
153 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
154 | }
155 | }
156 |
157 |
158 |
--------------------------------------------------------------------------------
/demos/radio-buttons/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MixItUp Demo - Radio Buttons
10 |
11 |
12 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
92 |
93 |
--------------------------------------------------------------------------------
/demos/filtering-by-url/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .mixitup-control-active {
52 | background: #393939;
53 | }
54 |
55 | .mixitup-control-active[data-filter]:after {
56 | background: transparent;
57 | }
58 |
59 | .control:first-of-type {
60 | border-radius: 3px 0 0 3px;
61 | }
62 |
63 | .control:last-of-type {
64 | border-radius: 0 3px 3px 0;
65 | }
66 |
67 | .control[data-filter=".green"] {
68 | color: #91e6c7;
69 | }
70 |
71 | .control[data-filter=".blue"] {
72 | color: #5ecdde;
73 | }
74 |
75 | .control[data-filter=".pink"] {
76 | color: #d595aa;
77 | }
78 |
79 | .control[data-filter="none"] {
80 | color: #2f2f2f;
81 | }
82 |
83 | /* Container
84 | ---------------------------------------------------------------------- */
85 |
86 | .container {
87 | padding: 1rem;
88 | text-align: justify;
89 | font-size: 0.1px;
90 | }
91 |
92 | .container:after {
93 | content: '';
94 | display: inline-block;
95 | width: 100%;
96 | }
97 |
98 | /* Target Elements
99 | ---------------------------------------------------------------------- */
100 |
101 | .mix,
102 | .gap {
103 | display: inline-block;
104 | vertical-align: top;
105 | }
106 |
107 | .mix {
108 | background: #fff;
109 | border-top: .5rem solid currentColor;
110 | border-radius: 2px;
111 | margin-bottom: 1rem;
112 | position: relative;
113 | }
114 |
115 | .mix:before {
116 | content: '';
117 | display: inline-block;
118 | padding-top: 56.25%;
119 | }
120 |
121 | .mix.green {
122 | color: #91e6c7;
123 | }
124 |
125 | .mix.pink {
126 | color: #d595aa;
127 | }
128 |
129 | .mix.blue {
130 | color: #5ecdde;
131 | }
132 |
133 | /* Grid Breakpoints
134 | ---------------------------------------------------------------------- */
135 |
136 | /* 2 Columns */
137 |
138 | .mix,
139 | .gap {
140 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
141 | }
142 |
143 | /* 3 Columns */
144 |
145 | @media screen and (min-width: 541px) {
146 | .mix,
147 | .gap {
148 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
149 | }
150 | }
151 |
152 | /* 4 Columns */
153 |
154 | @media screen and (min-width: 961px) {
155 | .mix,
156 | .gap {
157 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
158 | }
159 | }
160 |
161 | /* 5 Columns */
162 |
163 | @media screen and (min-width: 1281px) {
164 | .mix,
165 | .gap {
166 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
167 | }
168 | }
169 |
170 |
171 |
--------------------------------------------------------------------------------
/demos/sorting-by-multiple-attributes/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-sort]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | border-top: 2px solid;
44 | border-left: 2px solid;
45 | top: calc(50% - 6px);
46 | left: calc(50% - 6px);
47 | transform: translateY(1px) rotate(45deg);
48 | }
49 |
50 | .control[data-sort*=":desc"]:after {
51 | transform: translateY(-4px) rotate(-135deg);
52 | }
53 |
54 | .mixitup-control-active {
55 | background: #393939;
56 | }
57 |
58 | .mixitup-control-active[data-filter]:after {
59 | background: transparent;
60 | }
61 |
62 | .control:first-of-type {
63 | border-radius: 3px 0 0 3px;
64 | }
65 |
66 | .control:last-of-type {
67 | border-radius: 0 3px 3px 0;
68 | }
69 |
70 | /* Container
71 | ---------------------------------------------------------------------- */
72 |
73 | .container {
74 | padding: 1rem;
75 | text-align: justify;
76 | font-size: 0.1px;
77 | }
78 |
79 | .container:after {
80 | content: '';
81 | display: inline-block;
82 | width: 100%;
83 | }
84 |
85 | /* Target Elements
86 | ---------------------------------------------------------------------- */
87 |
88 | .mix,
89 | .gap {
90 | display: inline-block;
91 | vertical-align: top;
92 | }
93 |
94 | .mix {
95 | background: #fff;
96 | border-radius: 2px;
97 | margin-bottom: 1rem;
98 | position: relative;
99 | font-family: 'helvetica-neue', arial, sans-serif;
100 | font-size: 1rem;
101 | font-weight: bold;
102 | color: #aaa;
103 | }
104 |
105 | .mix:before {
106 | content: '';
107 | display: inline-block;
108 | padding-top: 56.25%;
109 | }
110 |
111 | .mix[data-published-date]:after {
112 | position: absolute;
113 | content: attr(data-published-date);
114 | padding: 1rem;
115 | width: 100%;
116 | top: 0;
117 | left: 0;
118 | }
119 |
120 | .mix h4 {
121 | position: absolute;
122 | padding: 1rem;
123 | bottom: 0;
124 | left: 0;
125 | color: #333;
126 | }
127 |
128 | /* Grid Breakpoints
129 | ---------------------------------------------------------------------- */
130 |
131 | /* 2 Columns */
132 |
133 | .mix,
134 | .gap {
135 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
136 | }
137 |
138 | /* 3 Columns */
139 |
140 | @media screen and (min-width: 541px) {
141 | .mix,
142 | .gap {
143 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
144 | }
145 | }
146 |
147 | /* 4 Columns */
148 |
149 | @media screen and (min-width: 961px) {
150 | .mix,
151 | .gap {
152 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
153 | }
154 | }
155 |
156 | /* 5 Columns */
157 |
158 | @media screen and (min-width: 1281px) {
159 | .mix,
160 | .gap {
161 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
162 | }
163 | }
164 |
165 |
166 |
--------------------------------------------------------------------------------
/demos/toggle-filtering-or-logic/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after,
39 | .control[data-toggle]:after {
40 | content: '';
41 | position: absolute;
42 | width: 10px;
43 | height: 10px;
44 | top: calc(50% - 6px);
45 | left: calc(50% - 6px);
46 | border: 2px solid currentColor;
47 | border-radius: 2px;
48 | background: currentColor;
49 | transition: background-color 150ms, border-color 150ms;
50 | }
51 |
52 | .mixitup-control-active {
53 | background: #393939;
54 | }
55 |
56 | .mixitup-control-active[data-toggle]:after {
57 | background: transparent;
58 | }
59 |
60 | .control:first-of-type {
61 | border-radius: 3px 0 0 3px;
62 | }
63 |
64 | .control:last-of-type {
65 | border-radius: 0 3px 3px 0;
66 | }
67 |
68 | .control[data-filter=".green"],
69 | .control[data-toggle=".green"] {
70 | color: #91e6c7;
71 | }
72 |
73 | .control[data-filter=".blue"],
74 | .control[data-toggle=".blue"] {
75 | color: #5ecdde;
76 | }
77 |
78 | .control[data-filter=".pink"],
79 | .control[data-toggle=".pink"] {
80 | color: #d595aa;
81 | }
82 |
83 | /* Container
84 | ---------------------------------------------------------------------- */
85 |
86 | .container {
87 | padding: 1rem;
88 | text-align: justify;
89 | font-size: 0.1px;
90 | }
91 |
92 | .container:after {
93 | content: '';
94 | display: inline-block;
95 | width: 100%;
96 | }
97 |
98 | /* Target Elements
99 | ---------------------------------------------------------------------- */
100 |
101 | .mix,
102 | .gap {
103 | display: inline-block;
104 | vertical-align: top;
105 | }
106 |
107 | .mix {
108 | background: #fff;
109 | border-top: .5rem solid currentColor;
110 | border-radius: 2px;
111 | margin-bottom: 1rem;
112 | position: relative;
113 | }
114 |
115 | .mix:before {
116 | content: '';
117 | display: inline-block;
118 | padding-top: 56.25%;
119 | }
120 |
121 | .mix.green {
122 | color: #91e6c7;
123 | }
124 |
125 | .mix.pink {
126 | color: #d595aa;
127 | }
128 |
129 | .mix.blue {
130 | color: #5ecdde;
131 | }
132 |
133 | /* Grid Breakpoints
134 | ---------------------------------------------------------------------- */
135 |
136 | /* 2 Columns */
137 |
138 | .mix,
139 | .gap {
140 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
141 | }
142 |
143 | /* 3 Columns */
144 |
145 | @media screen and (min-width: 541px) {
146 | .mix,
147 | .gap {
148 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
149 | }
150 | }
151 |
152 | /* 4 Columns */
153 |
154 | @media screen and (min-width: 961px) {
155 | .mix,
156 | .gap {
157 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
158 | }
159 | }
160 |
161 | /* 5 Columns */
162 |
163 | @media screen and (min-width: 1281px) {
164 | .mix,
165 | .gap {
166 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
167 | }
168 | }
169 |
170 |
171 |
--------------------------------------------------------------------------------
/demos/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MixItUp Demos
5 |
6 |
7 | MixItUp Demos
8 |
9 | The following collection of demos have been designed to demonstrate MixItUp's core functionality. They are maintained as part of the MixItUp Github repository , and can be viewed at patrickkunka.github.io/mixitup/demos/ .
10 |
11 | Each demo is intended to be as simple and instructive as possible and therefore intentionally avoids "magic" such as SASS, ES6, modules, or external dependencies that may require compilation in order to be usable in the browser. As such, you may run and edit these demos using any basic static file webserver, online or offline.
12 |
13 | Basic Functionality
14 |
15 |
22 |
23 | Filtering
24 |
25 |
31 |
32 | Non-standard UI
33 |
34 |
41 |
42 | Sorting
43 |
44 |
49 |
50 | Insertion
51 |
52 |
55 |
56 | Removal
57 |
58 |
61 |
62 | Dataset
63 |
64 |
68 |
69 | Grids
70 |
71 |
78 |
79 |
--------------------------------------------------------------------------------
/demos/insertion-non-target-elements/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .control[data-sort]:after {
52 | content: '';
53 | position: absolute;
54 | width: 10px;
55 | height: 10px;
56 | border-top: 2px solid;
57 | border-left: 2px solid;
58 | top: calc(50% - 6px);
59 | left: calc(50% - 6px);
60 | transform: translateY(1px) rotate(45deg);
61 | }
62 |
63 | .control[data-sort*=":desc"]:after {
64 | transform: translateY(-4px) rotate(-135deg);
65 | }
66 |
67 | .mixitup-control-active {
68 | background: #393939;
69 | }
70 |
71 | .control:first-of-type {
72 | border-radius: 3px 0 0 3px;
73 | }
74 |
75 | .control:last-of-type {
76 | border-radius: 0 3px 3px 0;
77 | }
78 |
79 | /* Container
80 | ---------------------------------------------------------------------- */
81 |
82 | .container {
83 | padding: 1rem;
84 | text-align: justify;
85 | font-size: 0.1px;
86 | }
87 |
88 | .container:after {
89 | content: '';
90 | display: inline-block;
91 | width: 100%;
92 | }
93 |
94 | /* Grid Elements
95 | ---------------------------------------------------------------------- */
96 |
97 | .item,
98 | .gap {
99 | display: inline-block;
100 | vertical-align: top;
101 | }
102 |
103 | .item {
104 | background: #fff;
105 | border-radius: 2px;
106 | margin-bottom: 1rem;
107 | position: relative;
108 | }
109 |
110 | .item:before {
111 | content: '';
112 | display: inline-block;
113 | vertical-align: middle;
114 | padding-top: 100%;
115 | }
116 |
117 | .button {
118 | background: #ddd;
119 | font-size: 4rem;
120 | font-weight: bold;
121 | text-align: center;
122 | cursor: pointer;
123 | transition: box-shadow 100ms;
124 | }
125 |
126 | .button:hover {
127 | box-shadow: inset 0 0 20px rgba(0,0,0, .1);
128 | }
129 |
130 | .button:after {
131 | display: inline-block;
132 | content: '+';
133 | font-size: 4rem;
134 | color: #bbb;
135 | }
136 |
137 | /* Grid Breakpoints
138 | ---------------------------------------------------------------------- */
139 |
140 | /* 2 Columns */
141 |
142 | .item,
143 | .gap {
144 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
145 | }
146 |
147 | /* 3 Columns */
148 |
149 | @media screen and (min-width: 541px) {
150 | .item,
151 | .gap {
152 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
153 | }
154 | }
155 |
156 | /* 4 Columns */
157 |
158 | @media screen and (min-width: 961px) {
159 | .item,
160 | .gap {
161 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
162 | }
163 | }
164 |
165 | /* 5 Columns */
166 |
167 | @media screen and (min-width: 1281px) {
168 | .item,
169 | .gap {
170 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
171 | }
172 | }
173 |
174 |
175 |
--------------------------------------------------------------------------------
/tests/unit/mixer-get-state.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 |
11 | describe('mixitup.Mixer', () => {
12 | describe('#getState()', () => {
13 | let container = dom.getContainer();
14 | let id = container.id = 'test-id';
15 | let mixer = mixitup(container);
16 | let state = mixer.getState();
17 |
18 | after(() => mixer.destroy());
19 |
20 | it('should contain an id equal to the container id', () => {
21 | chai.assert.equal(state.container.id, id);
22 | });
23 |
24 | it('should contain a reference to the container element', () => {
25 | chai.assert.equal(state.container, container);
26 | });
27 |
28 | it('should contain a reference to the container element', () => {
29 | chai.assert.equal(state.container, container);
30 | });
31 |
32 | it('should contain an activeFilter object with the default selector active', () => {
33 | chai.assert.instanceOf(state.activeFilter, mixitup.CommandFilter);
34 | chai.assert.equal(state.activeFilter.selector, '.mix');
35 | });
36 |
37 | it('should contain an activeSort object with the default sort string active', () => {
38 | chai.assert.instanceOf(state.activeSort, mixitup.CommandSort);
39 | chai.assert.equal(state.activeSort.sortString, 'default:asc');
40 | });
41 |
42 | it('should contain an empty activeContainerClassName string', () => {
43 | chai.assert.equal(state.activeContainerClassName, '');
44 | });
45 |
46 | it('should contain a null activeDataset', () => {
47 | chai.assert.deepEqual(state.activeDataset, null);
48 | });
49 |
50 | it('should contain a hasFailed boolean, set to false', () => {
51 | chai.assert.deepEqual(state.hasFailed, false);
52 | });
53 |
54 | it('should contain a list of targets deeply equaling the contents of the container', () => {
55 | chai.assert.deepEqual(state.targets, Array.prototype.slice.apply(container.children));
56 | });
57 |
58 | it('should contain a totalTargets integer, equal to the number of targets in the container', () => {
59 | chai.assert.equal(state.totalTargets, container.children.length);
60 | });
61 |
62 | it('should contain a list of targets currently shown', () => {
63 | chai.assert.deepEqual(state.show, Array.prototype.slice.apply(container.children));
64 | chai.assert.deepEqual(state.show, state.targets);
65 | });
66 |
67 | it('should contain a totalShow integer, equal to the number of targets shown', () => {
68 | chai.assert.equal(state.totalShow, container.children.length);
69 | });
70 |
71 | it('should contain a list of targets matching the active selector', () => {
72 | chai.assert.deepEqual(state.matching, Array.prototype.slice.apply(container.children));
73 | chai.assert.deepEqual(state.matching, state.targets);
74 | });
75 |
76 | it('should contain a totalMatching integer, equal to the number of targets matching the active selector', () => {
77 | chai.assert.equal(state.totalMatching, container.children.length);
78 | });
79 |
80 | it('should contain a list of targets currently hidden', () => {
81 | chai.assert.deepEqual(state.hide, []);
82 | });
83 |
84 | it('should contain a totalShow integer, equal to the number of targets hidden', () => {
85 | chai.assert.equal(state.totalHide, 0);
86 | });
87 |
88 | it('should contain a null triggerElement reference', () => {
89 | chai.assert.equal(state.triggerElement, null);
90 | });
91 | });
92 | });
--------------------------------------------------------------------------------
/src/config-load.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A group of properties defining the initial state of the mixer on load (instantiation).
5 | *
6 | * @constructor
7 | * @memberof mixitup.Config
8 | * @name load
9 | * @namespace
10 | * @public
11 | * @since 2.0.0
12 | */
13 |
14 | mixitup.ConfigLoad = function() {
15 | mixitup.Base.call(this);
16 |
17 | this.callActions('beforeConstruct');
18 |
19 | /**
20 | * A string defining any filtering to be statically applied to the mixer on load.
21 | * As per the `.filter()` API, this can be any valid selector string, or the
22 | * values `'all'` or `'none'`.
23 | *
24 | * @example Example 1: Defining an initial filter selector to be applied on load
25 | *
26 | * // The mixer will show only those targets matching '.category-a' on load.
27 | *
28 | * var mixer = mixitup(containerEl, {
29 | * load: {
30 | * filter: '.category-a'
31 | * }
32 | * });
33 | *
34 | * @example Example 2: Hiding all targets on load
35 | *
36 | * // The mixer will show hide all targets on load.
37 | *
38 | * var mixer = mixitup(containerEl, {
39 | * load: {
40 | * filter: 'none'
41 | * }
42 | * });
43 | *
44 | * @name filter
45 | * @memberof mixitup.Config.load
46 | * @instance
47 | * @type {string}
48 | * @default 'all'
49 | */
50 |
51 | this.filter = 'all';
52 |
53 | /**
54 | * A string defining any sorting to be statically applied to the mixer on load.
55 | * As per the `.sort()` API, this should be a valid "sort string" made up of
56 | * an attribute to sort by (or `'default'`) followed by an optional sorting
57 | * order, or the value `'random'`;
58 | *
59 | * @example Example: Defining sorting to be applied on load
60 | *
61 | * // The mixer will sort the container by the value of the `data-published-date`
62 | * // attribute, in descending order.
63 | *
64 | * var mixer = mixitup(containerEl, {
65 | * load: {
66 | * sort: 'published-date:desc'
67 | * }
68 | * });
69 | *
70 | * @name sort
71 | * @memberof mixitup.Config.load
72 | * @instance
73 | * @type {string}
74 | * @default 'default:asc'
75 | */
76 |
77 | this.sort = 'default:asc';
78 |
79 | /**
80 | * An array of objects representing the underlying data of any pre-rendered targets,
81 | * when using the `.dataset()` API.
82 | *
83 | * NB: If targets are pre-rendered when the mixer is instantiated, this must be set.
84 | *
85 | * @example Example: Defining the initial underyling dataset
86 | *
87 | * var myDataset = [
88 | * {
89 | * id: 0,
90 | * title: "Blog Post Title 0",
91 | * ...
92 | * },
93 | * {
94 | * id: 1,
95 | * title: "Blog Post Title 1",
96 | * ...
97 | * }
98 | * ];
99 | *
100 | * var mixer = mixitup(containerEl, {
101 | * data: {
102 | * uidKey: 'id'
103 | * },
104 | * load: {
105 | * dataset: myDataset
106 | * }
107 | * });
108 | *
109 | * @name dataset
110 | * @memberof mixitup.Config.load
111 | * @instance
112 | * @type {Array.}
113 | * @default null
114 | */
115 |
116 | this.dataset = null;
117 |
118 | this.callActions('afterConstruct');
119 |
120 | h.seal(this);
121 | };
122 |
123 | mixitup.BaseStatic.call(mixitup.ConfigLoad);
124 |
125 | mixitup.ConfigLoad.prototype = Object.create(mixitup.Base.prototype);
126 |
127 | mixitup.ConfigLoad.prototype.constructor = mixitup.ConfigLoad;
--------------------------------------------------------------------------------
/docs/mixitup-3-migration-guide.md:
--------------------------------------------------------------------------------
1 | # MixItUp 3 Migration Guide
2 |
3 | The biggest change to MixItUp with v3, is the dropping of jQuery as a dependency. MixItUp 1 and 2 both existed as jQuery plugins, with instantiation and API calls abstracted away through a typical jQuery-plugin interface.
4 |
5 | With MixItUp 3, we can now interact with MixItUp instances ('mixers') directly with minimal abstraction.
6 |
7 | ## Instantiation
8 |
9 | ###### Example: Basic Instantiation
10 |
11 | ```js
12 | // MixItUp 2
13 |
14 | $('.container').mixItUp();
15 | ```
16 |
17 | ```js
18 | // MixItUp 3
19 |
20 | var mixer = mixitup('.container');
21 | ```
22 |
23 | ###### Example: Passing the configuration object
24 |
25 | ```js
26 | // MixItUp 2
27 |
28 | $('.container').mixItUp({
29 | selectors: {
30 | target: '.item'
31 | }
32 | });
33 | ```
34 |
35 | ```js
36 | // MixItUp 3
37 |
38 | var mixer = mixitup('.container', {
39 | selectors: {
40 | target: '.item'
41 | }
42 | });
43 | ```
44 |
45 | Note that the `mixitup()` factory function is now all lowercase, as apposed to the camel case MixItUp 2 jQuery method `.mixItUp()`.
46 |
47 | MixItUp 3 adds many new configuration options, and renames or removes some of those from MixItUp 2.
48 |
49 | *Further reading: [Configuration Object](/docs/mixitup.Config.md)*
50 |
51 | ## Method Invocation
52 |
53 | ```js
54 | // MixItUp 2
55 |
56 | $('.container').mixItUp('filter', '.category-a');
57 | ```
58 | ```js
59 | // MixItUp 3
60 |
61 | mixer.filter('.category-a');
62 | ```
63 |
64 | As you may have noticed, mixers in MixItUp 3 have many of the same API methods as were available in MixItUp 2, but are called using standard method invocation syntax, with arguments passed in the standard form rather than the jQuery-UI-like syntax of MixItUp 2.
65 |
66 | MixItUp 3 adds many new API methods, and renames or removes some of those from MixItUp 2.
67 |
68 | *Further reading: [Mixer API Methods](/docs/mixitup.Mixer.md)*
69 |
70 | ## Promises and Callbacks
71 |
72 | In MixItUp 2, asynchronous operations (those involving animation) accepted an optional callback function to be invoked on completion.
73 |
74 | With MixItUp 3, all asynchronous methods return a promise resolving with a state object. Callback functions are still permitted as an optional argument, but promises should be considered the preferred method for dealing with asynchronous operations.
75 |
76 | ```js
77 | // MixItUp 2 (callbacks)
78 |
79 | $('.container').mixItUp('filter', '.category-a', function(state) {
80 | // Operation finished, the new state is:
81 |
82 | console.log(state);
83 | });
84 | ```
85 |
86 | ```js
87 | // MixItUp 3 (promises)
88 |
89 | mixer.filter('.category-a')
90 | .then(function(state) {
91 | // Operation finished, the new state is:
92 |
93 | console.log(state);
94 | });
95 | ```
96 |
97 | ## CSS
98 |
99 | In MixItUp 2, it was required that a CSS `display: none` rule be applied to all target elements by default, with MixItUp adding the `display` value of your choice (e.g. `inline-block`) to only those targets to be shown. This was intended to prevent a flash-of-content before MixItUp 2's loading animation started.
100 |
101 | With MixItUp 3, loading animations are removed by default, and mixers are instantiated synchronously and instantly. Because of this, it is assumed that all targets in the DOM are already shown, so MixItUp only needs to add `display: none` to those targets to be hidden, using whatever `display` value is declared in your CSS for shown targets.
102 |
103 | In short – you no longer need to set `display: none` in your CSS. Simply use whatever display value your layout would require, regardless of MixItUp.
104 |
105 | Loading animations are still possible in MixItUp 3 as demonstrated in the [Loading Animation](http://patrickkunka.github.io/mixitup/demos/loading-animation/) demo. The code for this demo is available [here](../demos/loading-animation/index.html).
106 |
--------------------------------------------------------------------------------
/demos/toggle-filtering-and-logic/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after,
39 | .control[data-toggle]:after {
40 | content: '';
41 | position: absolute;
42 | width: 10px;
43 | height: 10px;
44 | top: calc(50% - 6px);
45 | left: calc(50% - 6px);
46 | border: 2px solid currentColor;
47 | border-radius: 2px;
48 | background: currentColor;
49 | transition: background-color 150ms, border-color 150ms;
50 | }
51 |
52 | .mixitup-control-active {
53 | background: #393939;
54 | }
55 |
56 | .mixitup-control-active[data-toggle]:after {
57 | background: transparent;
58 | }
59 |
60 | .control:first-of-type {
61 | border-radius: 3px 0 0 3px;
62 | }
63 |
64 | .control:last-of-type {
65 | border-radius: 0 3px 3px 0;
66 | }
67 |
68 | .control[data-filter=".green"],
69 | .control[data-toggle=".green"] {
70 | color: #91e6c7;
71 | }
72 |
73 | .control[data-filter=".blue"],
74 | .control[data-toggle=".blue"] {
75 | color: #5ecdde;
76 | }
77 |
78 | .control[data-filter=".pink"],
79 | .control[data-toggle=".pink"] {
80 | color: #d595aa;
81 | }
82 |
83 | /* Container
84 | ---------------------------------------------------------------------- */
85 |
86 | .container {
87 | padding: 1rem;
88 | text-align: justify;
89 | font-size: 0.1px;
90 | }
91 |
92 | .container:after {
93 | content: '';
94 | display: inline-block;
95 | width: 100%;
96 | }
97 |
98 | /* Target Elements
99 | ---------------------------------------------------------------------- */
100 |
101 | .mix,
102 | .gap {
103 | display: inline-block;
104 | vertical-align: top;
105 | }
106 |
107 | .mix {
108 | background: #fff;
109 | border-top: .5rem solid currentColor;
110 | border-radius: 2px;
111 | margin-bottom: 1rem;
112 | position: relative;
113 | }
114 |
115 | .mix:before {
116 | content: '';
117 | display: inline-block;
118 | padding-top: 56.25%;
119 | border-top: .5rem solid transparent;
120 | }
121 |
122 | .mix.green {
123 | color: #91e6c7;
124 | }
125 |
126 | .mix.pink {
127 | color: #d595aa;
128 | }
129 |
130 | .mix.blue {
131 | color: #5ecdde;
132 | }
133 |
134 | .mix.pink.green:before {
135 | width: 100%;
136 | border-top-color: #91e6c7;
137 | }
138 |
139 | .mix.green.blue:before {
140 | width: 100%;
141 | border-top-color: #91e6c7;
142 | }
143 |
144 | .mix.blue.pink:before {
145 | width: 100%;
146 | border-top-color: #d595aa;
147 | }
148 |
149 | /* Grid Breakpoints
150 | ---------------------------------------------------------------------- */
151 |
152 | /* 2 Columns */
153 |
154 | .mix,
155 | .gap {
156 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
157 | }
158 |
159 | /* 3 Columns */
160 |
161 | @media screen and (min-width: 541px) {
162 | .mix,
163 | .gap {
164 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
165 | }
166 | }
167 |
168 | /* 4 Columns */
169 |
170 | @media screen and (min-width: 961px) {
171 | .mix,
172 | .gap {
173 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
174 | }
175 | }
176 |
177 | /* 5 Columns */
178 |
179 | @media screen and (min-width: 1281px) {
180 | .mix,
181 | .gap {
182 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
183 | }
184 | }
185 |
186 |
187 |
--------------------------------------------------------------------------------
/demos/multiple-instances-global-control-scoping/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | font-size: 0.1px;
18 | margin-bottom: 1rem;
19 | padding: 1rem;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .control[data-sort]:after {
52 | content: '';
53 | position: absolute;
54 | width: 10px;
55 | height: 10px;
56 | border-top: 2px solid;
57 | border-left: 2px solid;
58 | top: calc(50% - 6px);
59 | left: calc(50% - 6px);
60 | transform: translateY(1px) rotate(45deg);
61 | }
62 |
63 | .control[data-sort*=":desc"]:after {
64 | transform: translateY(-4px) rotate(-135deg);
65 | }
66 |
67 | .mixitup-control-active {
68 | background: #393939;
69 | }
70 |
71 | .mixitup-control-active[data-filter]:after {
72 | background: transparent;
73 | }
74 |
75 | .control:first-of-type {
76 | border-radius: 3px 0 0 3px;
77 | }
78 |
79 | .control:last-of-type {
80 | border-radius: 0 3px 3px 0;
81 | }
82 |
83 | .control[data-filter=".green"] {
84 | color: #91e6c7;
85 | }
86 |
87 | .control[data-filter=".blue"] {
88 | color: #5ecdde;
89 | }
90 |
91 | .control[data-filter=".pink"] {
92 | color: #d595aa;
93 | }
94 |
95 | .control[data-filter="none"] {
96 | color: #2f2f2f;
97 | }
98 |
99 | /* Container
100 | ---------------------------------------------------------------------- */
101 |
102 | .container {
103 | padding: 1rem;
104 | text-align: justify;
105 | font-size: 0.1px;
106 | }
107 |
108 | .targets:after {
109 | content: '';
110 | display: inline-block;
111 | width: 100%;
112 | }
113 |
114 | /* Target Elements
115 | ---------------------------------------------------------------------- */
116 |
117 | .mix,
118 | .gap {
119 | display: inline-block;
120 | vertical-align: top;
121 | }
122 |
123 | .mix {
124 | background: #fff;
125 | border-top: .5rem solid currentColor;
126 | border-radius: 2px;
127 | margin-bottom: 1rem;
128 | position: relative;
129 | }
130 |
131 | .mix:before {
132 | content: '';
133 | display: inline-block;
134 | padding-top: 56.25%;
135 | }
136 |
137 | .mix.green {
138 | color: #91e6c7;
139 | }
140 |
141 | .mix.pink {
142 | color: #d595aa;
143 | }
144 |
145 | .mix.blue {
146 | color: #5ecdde;
147 | }
148 |
149 | /* Grid Breakpoints
150 | ---------------------------------------------------------------------- */
151 |
152 | /* 2 Columns */
153 |
154 | .mix,
155 | .gap {
156 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
157 | }
158 |
159 | /* 3 Columns */
160 |
161 | @media screen and (min-width: 541px) {
162 | .mix,
163 | .gap {
164 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
165 | }
166 | }
167 |
168 | /* 4 Columns */
169 |
170 | @media screen and (min-width: 961px) {
171 | .mix,
172 | .gap {
173 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
174 | }
175 | }
176 |
177 | /* 5 Columns */
178 |
179 | @media screen and (min-width: 1281px) {
180 | .mix,
181 | .gap {
182 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
183 | }
184 | }
--------------------------------------------------------------------------------
/demos/multiple-instances-local-control-scoping/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | font-size: 0.1px;
18 | margin-bottom: 1rem;
19 | }
20 |
21 | .control {
22 | position: relative;
23 | display: inline-block;
24 | width: 2.7rem;
25 | height: 2.7rem;
26 | background: #444;
27 | cursor: pointer;
28 | font-size: 0.1px;
29 | color: white;
30 | transition: background 150ms;
31 | }
32 |
33 | .control:hover {
34 | background: #3f3f3f;
35 | }
36 |
37 | .control[data-filter]:after {
38 | content: '';
39 | position: absolute;
40 | width: 10px;
41 | height: 10px;
42 | top: calc(50% - 6px);
43 | left: calc(50% - 6px);
44 | border: 2px solid currentColor;
45 | border-radius: 2px;
46 | background: currentColor;
47 | transition: background-color 150ms, border-color 150ms;
48 | }
49 |
50 | .control[data-sort]:after {
51 | content: '';
52 | position: absolute;
53 | width: 10px;
54 | height: 10px;
55 | border-top: 2px solid;
56 | border-left: 2px solid;
57 | top: calc(50% - 6px);
58 | left: calc(50% - 6px);
59 | transform: translateY(1px) rotate(45deg);
60 | }
61 |
62 | .control[data-sort*=":desc"]:after {
63 | transform: translateY(-4px) rotate(-135deg);
64 | }
65 |
66 | .mixitup-control-active {
67 | background: #393939;
68 | }
69 |
70 | .mixitup-control-active[data-filter]:after {
71 | background: transparent;
72 | }
73 |
74 | .control:first-of-type {
75 | border-radius: 3px 0 0 3px;
76 | }
77 |
78 | .control:last-of-type {
79 | border-radius: 0 3px 3px 0;
80 | }
81 |
82 | .control[data-filter=".green"] {
83 | color: #91e6c7;
84 | }
85 |
86 | .control[data-filter=".blue"] {
87 | color: #5ecdde;
88 | }
89 |
90 | .control[data-filter=".pink"] {
91 | color: #d595aa;
92 | }
93 |
94 | .control[data-filter="none"] {
95 | color: #2f2f2f;
96 | }
97 |
98 | /* Container
99 | ---------------------------------------------------------------------- */
100 |
101 | .container {
102 | padding: 1rem;
103 | }
104 |
105 | .targets {
106 | text-align: justify;
107 | font-size: 0.1px;
108 | }
109 |
110 | .targets:after {
111 | content: '';
112 | display: inline-block;
113 | width: 100%;
114 | }
115 |
116 | /* Target Elements
117 | ---------------------------------------------------------------------- */
118 |
119 | .mix,
120 | .gap {
121 | display: inline-block;
122 | vertical-align: top;
123 | }
124 |
125 | .mix {
126 | background: #fff;
127 | border-top: .5rem solid currentColor;
128 | border-radius: 2px;
129 | margin-bottom: 1rem;
130 | position: relative;
131 | }
132 |
133 | .mix:before {
134 | content: '';
135 | display: inline-block;
136 | padding-top: 56.25%;
137 | }
138 |
139 | .mix.green {
140 | color: #91e6c7;
141 | }
142 |
143 | .mix.pink {
144 | color: #d595aa;
145 | }
146 |
147 | .mix.blue {
148 | color: #5ecdde;
149 | }
150 |
151 | /* Grid Breakpoints
152 | ---------------------------------------------------------------------- */
153 |
154 | /* 2 Columns */
155 |
156 | .mix,
157 | .gap {
158 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
159 | }
160 |
161 | /* 3 Columns */
162 |
163 | @media screen and (min-width: 541px) {
164 | .mix,
165 | .gap {
166 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
167 | }
168 | }
169 |
170 | /* 4 Columns */
171 |
172 | @media screen and (min-width: 961px) {
173 | .mix,
174 | .gap {
175 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
176 | }
177 | }
178 |
179 | /* 5 Columns */
180 |
181 | @media screen and (min-width: 1281px) {
182 | .mix,
183 | .gap {
184 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
185 | }
186 | }
--------------------------------------------------------------------------------
/src/config-data.js:
--------------------------------------------------------------------------------
1 | /* global mixitup, h */
2 |
3 | /**
4 | * A group of properties relating to MixItUp's dataset API.
5 | *
6 | * @constructor
7 | * @memberof mixitup.Config
8 | * @name data
9 | * @namespace
10 | * @public
11 | * @since 3.0.0
12 | */
13 |
14 | mixitup.ConfigData = function() {
15 | mixitup.Base.call(this);
16 |
17 | this.callActions('beforeConstruct');
18 |
19 | /**
20 | * A string specifying the name of the key containing your data model's unique
21 | * identifier (UID). To use the dataset API, a UID key must be specified and
22 | * be present and unique on all objects in the dataset you provide to MixItUp.
23 | *
24 | * For example, if your dataset is made up of MongoDB documents, the UID
25 | * key would be `'id'` or `'_id'`.
26 | *
27 | * @example Example: Setting the UID to `'id'`
28 | * var mixer = mixitup(containerEl, {
29 | * data: {
30 | * uidKey: 'id'
31 | * }
32 | * });
33 | *
34 | * @name uidKey
35 | * @memberof mixitup.Config.data
36 | * @instance
37 | * @type {string}
38 | * @default ''
39 | */
40 |
41 | this.uidKey = '';
42 |
43 | /**
44 | * A boolean dictating whether or not MixItUp should "dirty check" each object in
45 | * your dataset for changes whenever `.dataset()` is called, and re-render any targets
46 | * for which a change is found.
47 | *
48 | * Depending on the complexity of your data model, dirty checking can be expensive
49 | * and is therefore disabled by default.
50 | *
51 | * NB: For changes to be detected, a new immutable instance of the edited model must be
52 | * provided to mixitup, rather than manipulating properties on the existing instance.
53 | * If your changes are a result of a DB write and read, you will most likely be calling
54 | * `.dataset()` with a clean set of objects each time, so this will not be an issue.
55 | *
56 | * @example Example: Enabling dirty checking
57 | *
58 | * var myDataset = [
59 | * {
60 | * id: 0,
61 | * title: "Blog Post Title 0"
62 | * ...
63 | * },
64 | * {
65 | * id: 1,
66 | * title: "Blog Post Title 1"
67 | * ...
68 | * }
69 | * ];
70 | *
71 | * // Instantiate a mixer with a pre-loaded dataset, and a target renderer
72 | * // function defined
73 | *
74 | * var mixer = mixitup(containerEl, {
75 | * data: {
76 | * uidKey: 'id',
77 | * dirtyCheck: true
78 | * },
79 | * load: {
80 | * dataset: myDataset
81 | * },
82 | * render: {
83 | * target: function() { ... }
84 | * }
85 | * });
86 | *
87 | * // For illustration, we will clone and edit the second object in the dataset.
88 | * // NB: this would typically be done server-side in response to a DB update,
89 | * and then re-queried via an API.
90 | *
91 | * myDataset[1] = Object.assign({}, myDataset[1]);
92 | *
93 | * myDataset[1].title = 'Blog Post Title 11';
94 | *
95 | * mixer.dataset(myDataset)
96 | * .then(function() {
97 | * // the target with ID "1", will be re-rendered reflecting its new title
98 | * });
99 | *
100 | * @name dirtyCheck
101 | * @memberof mixitup.Config.data
102 | * @instance
103 | * @type {boolean}
104 | * @default false
105 | */
106 |
107 | this.dirtyCheck = false;
108 |
109 | this.callActions('afterConstruct');
110 |
111 | h.seal(this);
112 | };
113 |
114 | mixitup.BaseStatic.call(mixitup.ConfigData);
115 |
116 | mixitup.ConfigData.prototype = Object.create(mixitup.Base.prototype);
117 |
118 | mixitup.ConfigData.prototype.constructor = mixitup.ConfigData;
--------------------------------------------------------------------------------
/demos/basic/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .control[data-sort]:after {
52 | content: '';
53 | position: absolute;
54 | width: 10px;
55 | height: 10px;
56 | border-top: 2px solid;
57 | border-left: 2px solid;
58 | top: calc(50% - 6px);
59 | left: calc(50% - 6px);
60 | transform: translateY(1px) rotate(45deg);
61 | }
62 |
63 | .control[data-sort*=":desc"]:after {
64 | transform: translateY(-4px) rotate(-135deg);
65 | }
66 |
67 | .mixitup-control-active {
68 | background: #393939;
69 | }
70 |
71 | .mixitup-control-active[data-filter]:after {
72 | background: transparent;
73 | }
74 |
75 | .control:first-of-type {
76 | border-radius: 3px 0 0 3px;
77 | }
78 |
79 | .control:last-of-type {
80 | border-radius: 0 3px 3px 0;
81 | }
82 |
83 | .control[data-filter] + .control[data-sort] {
84 | margin-left: .75rem;
85 | }
86 |
87 | .control[data-filter=".green"] {
88 | color: #91e6c7;
89 | }
90 |
91 | .control[data-filter=".blue"] {
92 | color: #5ecdde;
93 | }
94 |
95 | .control[data-filter=".pink"] {
96 | color: #d595aa;
97 | }
98 |
99 | .control[data-filter="none"] {
100 | color: #2f2f2f;
101 | }
102 |
103 | /* Container
104 | ---------------------------------------------------------------------- */
105 |
106 | .container {
107 | padding: 1rem;
108 | text-align: justify;
109 | font-size: 0.1px;
110 | }
111 |
112 | .container:after {
113 | content: '';
114 | display: inline-block;
115 | width: 100%;
116 | }
117 |
118 | /* Target Elements
119 | ---------------------------------------------------------------------- */
120 |
121 | .mix,
122 | .gap {
123 | display: inline-block;
124 | vertical-align: top;
125 | }
126 |
127 | .mix {
128 | background: #fff;
129 | border-top: .5rem solid currentColor;
130 | border-radius: 2px;
131 | margin-bottom: 1rem;
132 | position: relative;
133 | }
134 |
135 | .mix:before {
136 | content: '';
137 | display: inline-block;
138 | padding-top: 56.25%;
139 | }
140 |
141 | .mix.green {
142 | color: #91e6c7;
143 | }
144 |
145 | .mix.pink {
146 | color: #d595aa;
147 | }
148 |
149 | .mix.blue {
150 | color: #5ecdde;
151 | }
152 |
153 | /* Grid Breakpoints
154 | ---------------------------------------------------------------------- */
155 |
156 | /* 2 Columns */
157 |
158 | .mix,
159 | .gap {
160 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
161 | }
162 |
163 | /* 3 Columns */
164 |
165 | @media screen and (min-width: 541px) {
166 | .mix,
167 | .gap {
168 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
169 | }
170 | }
171 |
172 | /* 4 Columns */
173 |
174 | @media screen and (min-width: 961px) {
175 | .mix,
176 | .gap {
177 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
178 | }
179 | }
180 |
181 | /* 5 Columns */
182 |
183 | @media screen and (min-width: 1281px) {
184 | .mix,
185 | .gap {
186 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
187 | }
188 | }
189 |
190 |
191 |
--------------------------------------------------------------------------------
/demos/attribute-selectors/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .control[data-sort]:after {
52 | content: '';
53 | position: absolute;
54 | width: 10px;
55 | height: 10px;
56 | border-top: 2px solid;
57 | border-left: 2px solid;
58 | top: calc(50% - 6px);
59 | left: calc(50% - 6px);
60 | transform: translateY(1px) rotate(45deg);
61 | }
62 |
63 | .control[data-sort*=":desc"]:after {
64 | transform: translateY(-4px) rotate(-135deg);
65 | }
66 |
67 | .mixitup-control-active {
68 | background: #393939;
69 | }
70 |
71 | .mixitup-control-active[data-filter]:after {
72 | background: transparent;
73 | }
74 |
75 | .control:first-of-type {
76 | border-radius: 3px 0 0 3px;
77 | }
78 |
79 | .control:last-of-type {
80 | border-radius: 0 3px 3px 0;
81 | }
82 |
83 | .control[data-filter] + .control[data-sort] {
84 | margin-left: .75rem;
85 | }
86 |
87 | .control[data-filter=".green"] {
88 | color: #91e6c7;
89 | }
90 |
91 | .control[data-filter=".blue"] {
92 | color: #5ecdde;
93 | }
94 |
95 | .control[data-filter=".pink"] {
96 | color: #d595aa;
97 | }
98 |
99 | .control[data-filter="none"] {
100 | color: #2f2f2f;
101 | }
102 |
103 | /* Container
104 | ---------------------------------------------------------------------- */
105 |
106 | .container {
107 | padding: 1rem;
108 | text-align: justify;
109 | font-size: 0.1px;
110 | }
111 |
112 | .container:after {
113 | content: '';
114 | display: inline-block;
115 | width: 100%;
116 | }
117 |
118 | /* Grid Items
119 | ---------------------------------------------------------------------- */
120 |
121 | .item,
122 | .gap {
123 | display: inline-block;
124 | vertical-align: top;
125 | }
126 |
127 | .item {
128 | background: #fff;
129 | border-top: .5rem solid currentColor;
130 | border-radius: 2px;
131 | margin-bottom: 1rem;
132 | position: relative;
133 | }
134 |
135 | .item:before {
136 | content: '';
137 | display: inline-block;
138 | padding-top: 56.25%;
139 | }
140 |
141 | .item.green {
142 | color: #91e6c7;
143 | }
144 |
145 | .item.pink {
146 | color: #d595aa;
147 | }
148 |
149 | .item.blue {
150 | color: #5ecdde;
151 | }
152 |
153 | /* Grid Breakpoints
154 | ---------------------------------------------------------------------- */
155 |
156 | /* 2 Columns */
157 |
158 | .item,
159 | .gap {
160 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
161 | }
162 |
163 | /* 3 Columns */
164 |
165 | @media screen and (min-width: 541px) {
166 | .item,
167 | .gap {
168 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
169 | }
170 | }
171 |
172 | /* 4 Columns */
173 |
174 | @media screen and (min-width: 961px) {
175 | .item,
176 | .gap {
177 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
178 | }
179 | }
180 |
181 | /* 5 Columns */
182 |
183 | @media screen and (min-width: 1281px) {
184 | .item,
185 | .gap {
186 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
187 | }
188 | }
189 |
190 |
191 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | ## 3.3.2
5 | - Non run-time changes to licensing and distribution model
6 |
7 | ## 3.3.1
8 | - Insures dataset uses polyfilled `Array.from` for old IE support.
9 | - Fixes support for sorting via element collection. This was not correctly implemented before although documented.
10 | - Fixes the "filter-by-url" demo to ensure that only leading `'.'` characters are stripped off rather than any character.
11 |
12 | ## 3.3.0
13 | - Introduces new internal filter hook `testResultEvaluateHideShown` allowing plugins to manipulate the result of every filter test upon a target. Provides an convenient entry point for non-selector based filtering such as range slider inputs.
14 | - Adds range slider demo.
15 |
16 | ## 3.2.2
17 | - Fixes issue where multiple toggle controls are not automatically activated when a compound selector is specified to `load.filter`.
18 | - Fixes issue where calling `.toggleOff()` and passing a non-existent selector will deactivate all other active toggles.
19 | - Fixes issue where padding whitespace around a DOM string when calling `.insert()` caused an exception.
20 | - Adds additional demos for non-standard UI.
21 |
22 | ## 3.2.1
23 | - Additional edge-case work relating to Dataset API fix in v3.2.0.
24 | - Addition of `.forceRender()` mixer API method.
25 | - Removes `.multiMix()` legacy API alias method.
26 |
27 | ## 3.2.0
28 | - Removes support for legacy `$().mixItUp()` jQuery API
29 | - Fixes issue with Dataset API causing DOM exception when dealing with certain combinations of simultaneous insertion and sorting.
30 |
31 | ## 3.1.12
32 | - Fixes issue where `state.targets` does not reflect the updated sort order after a sort operation.
33 | - Addition of `behavior.liveSort` configuration option.
34 |
35 | ## 3.1.11
36 |
37 | - Various geometry improvements related to scroll bar issues on desktop Windows and (non-inertial scroll) desktop Mac systems.
38 | - Addition of `animation.clampWidth` configuration option.
39 |
40 | ## 3.1.10
41 |
42 | - Fixes an issue where the `activeContainerClass` did not persist between non-layout-change operations (e.g. sort, filter).
43 |
44 | ## 3.1.9
45 |
46 | - Fixes an issue relating to `animation.clampHeight` where the height was not correctly applied causing scroll jumping in certain situations.
47 |
48 | ## 3.1.8
49 |
50 | - Adds ability to bind live controls where multiple parents exist. Required for Pagination 3.2.0.
51 |
52 | ## 3.1.7
53 |
54 | - Fixed duplicate hook `beforeCacheDom` in `Target#cacheDom`. Now renamed to `afterCacheDom`.
55 |
56 | ## 3.1.6
57 |
58 | - Added composer.json
59 |
60 | ## 3.1.5
61 |
62 | - Fixed several issues relating to the Dataset API and multimix-like operations (i.e. simultaneous insertion/removal/sorting/dirty-checking)
63 |
64 | ## 3.1.4
65 |
66 | - Added ability to extend static factory methods (such as `mixitup.use`) with hooks.
67 | - Added ability to return a single DOM element from `render.target` instead of an HTML string
68 | - Moved target rendering functionality into `Target` class, so that targets can render themselves
69 | - Force disable controls if dataset API is in use (if `data.uidKey` is set)
70 |
71 | ## 3.1.3
72 |
73 | - Exposed `.toggleOn()` and `.toggleOff()` API methods publicly via the mixer facade, as were accidently missed out previously.
74 |
75 | ## 3.1.2
76 |
77 | - Improved `compareVersions` util function to handle semver notation correctly (e.g. `'^'`, `'~'`, `'-beta'`, etc).
78 | - Fixed issue with "Filtering by URL" demo that added a `#mix` segment to the URL for filter "all"
79 |
80 | ## 3.1.1
81 |
82 | - Fixed issue where `transitionend` event handlers were not rebound to re-rendered targets during dirtyCheck updates.
83 | - Fixed issue where dataset operation objects where created on push to queue, resulting in corrupted target data.
84 |
85 | ## 3.1.0
86 |
87 | - Added `selectors.controls` configuration option to allow for further specificity of control querying
88 | in addition to the mandatory data attributes.
89 | - Fixed package.json issues.
90 |
91 | ## 3.0.1
92 |
93 | - Fixed issue where `layout.containerClassName` is not reflected in state object after instantiation.
94 |
95 | ## 3.0.0
96 |
97 | - Release
--------------------------------------------------------------------------------
/tests/unit/mixer-remove.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('jsdom-global')();
4 |
5 | const chai = require('chai');
6 | const dom = require('../mock/dom');
7 | const mixitup = require('../../dist/mixitup.js');
8 |
9 | chai.use(require('chai-shallow-deep-equal'));
10 | chai.use(require('chai-as-promised'));
11 |
12 | describe('mixitup.Mixer', () => {
13 | describe('#remove()', () => {
14 | it('should accept an element as an argument', () => {
15 | const container = dom.getContainer();
16 | const mixer = mixitup(container);
17 | const toRemove = container.children[3];
18 |
19 | return mixer.remove(toRemove)
20 | .then(state => {
21 | chai.assert.notEqual(state.show[3].id, 'target-4');
22 | chai.assert.equal(state.show[3].id, 'target-5');
23 | chai.assert.equal(state.totalShow, '5');
24 |
25 | mixer.destroy();
26 | });
27 | });
28 |
29 | it('should accept a collection of elements as an argument', () => {
30 | const container = dom.getContainer();
31 | const mixer = mixitup(container);
32 | const toRemove = [container.children[3], container.children[0]];
33 |
34 | return mixer.remove(toRemove)
35 | .then(state => {
36 | chai.assert.equal(state.show[0].id, 'target-2');
37 | chai.assert.equal(state.show[3].id, 'target-6');
38 | chai.assert.equal(state.totalShow, '4');
39 |
40 | mixer.destroy();
41 | });
42 | });
43 |
44 | it('should accept an index as an argument', () => {
45 | const container = dom.getContainer();
46 | const mixer = mixitup(container);
47 |
48 | return mixer.remove(3)
49 | .then(state => {
50 | chai.assert.equal(state.show[3].id, 'target-5');
51 | chai.assert.equal(state.totalShow, '5');
52 |
53 | mixer.destroy();
54 | });
55 | });
56 |
57 | it('should accept a selector as an argument', () => {
58 | const container = dom.getContainer();
59 | const mixer = mixitup(container);
60 |
61 | return mixer.remove('.category-a')
62 | .then(state => {
63 | chai.assert.equal(state.totalShow, '3');
64 |
65 | mixer.destroy();
66 | });
67 | });
68 |
69 | it('should allow no elements to be removed with a warning', () => {
70 | const container = dom.getContainer();
71 | const mixer = mixitup(container);
72 |
73 | return mixer.remove()
74 | .then(state => {
75 | chai.assert.equal(state.totalShow, '6');
76 |
77 | mixer.destroy();
78 | });
79 | });
80 |
81 | it('should accept a callback function which is invoked after removal', () => {
82 | const container = dom.getContainer();
83 | const mixer = mixitup(container);
84 | const toRemove = container.children[0];
85 |
86 | const promise = new Promise(resolve => mixer.insert(mixer.remove(toRemove), resolve));
87 |
88 | chai.assert.isFulfilled(promise);
89 |
90 | return promise
91 | .then(() => {
92 | chai.assert.notEqual(toRemove, container);
93 |
94 | mixer.destroy();
95 | });
96 | });
97 |
98 | it('should accept a boolean allowing toggling off of animation', () => {
99 | const container = dom.getContainer();
100 | const mixer = mixitup(container);
101 | const toRemove = container.children[0];
102 |
103 | return mixer.remove(toRemove, false)
104 | .then(() => {
105 | chai.assert.notEqual(toRemove, container);
106 |
107 | mixer.destroy();
108 | });
109 | });
110 | });
111 | });
--------------------------------------------------------------------------------
/demos/removal-by-reference/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .control[data-sort]:after {
52 | content: '';
53 | position: absolute;
54 | width: 10px;
55 | height: 10px;
56 | border-top: 2px solid;
57 | border-left: 2px solid;
58 | top: calc(50% - 6px);
59 | left: calc(50% - 6px);
60 | transform: translateY(1px) rotate(45deg);
61 | }
62 |
63 | .control[data-sort*=":desc"]:after {
64 | transform: translateY(-4px) rotate(-135deg);
65 | }
66 |
67 | .mixitup-control-active {
68 | background: #393939;
69 | }
70 |
71 | .mixitup-control-active[data-filter]:after {
72 | background: transparent;
73 | }
74 |
75 | .control:first-of-type {
76 | border-radius: 3px 0 0 3px;
77 | }
78 |
79 | .control:last-of-type {
80 | border-radius: 0 3px 3px 0;
81 | }
82 |
83 | .control[data-filter] + .control[data-sort] {
84 | margin-left: .75rem;
85 | }
86 |
87 | .control[data-filter=".green"] {
88 | color: #91e6c7;
89 | }
90 |
91 | .control[data-filter=".blue"] {
92 | color: #5ecdde;
93 | }
94 |
95 | .control[data-filter=".pink"] {
96 | color: #d595aa;
97 | }
98 |
99 | .control[data-filter="none"] {
100 | color: #2f2f2f;
101 | }
102 |
103 | /* Container
104 | ---------------------------------------------------------------------- */
105 |
106 | .container {
107 | padding: 1rem;
108 | text-align: justify;
109 | font-size: 0.1px;
110 | }
111 |
112 | .container:after {
113 | content: '';
114 | display: inline-block;
115 | width: 100%;
116 | }
117 |
118 | /* Target Elements
119 | ---------------------------------------------------------------------- */
120 |
121 | .mix,
122 | .gap {
123 | display: inline-block;
124 | vertical-align: top;
125 | }
126 |
127 | .mix {
128 | background: #fff;
129 | border-top: .5rem solid currentColor;
130 | border-radius: 2px;
131 | margin-bottom: 1rem;
132 | position: relative;
133 | cursor: pointer;
134 | transition: opacity 150ms;
135 | }
136 |
137 | .mix:before {
138 | content: '';
139 | display: inline-block;
140 | padding-top: 56.25%;
141 | }
142 |
143 | .mix.green {
144 | color: #91e6c7;
145 | }
146 |
147 | .mix.pink {
148 | color: #d595aa;
149 | }
150 |
151 | .mix.blue {
152 | color: #5ecdde;
153 | }
154 |
155 | .mix:hover {
156 | opacity: 0.5;
157 | }
158 |
159 | /* Grid Breakpoints
160 | ---------------------------------------------------------------------- */
161 |
162 | /* 2 Columns */
163 |
164 | .mix,
165 | .gap {
166 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
167 | }
168 |
169 | /* 3 Columns */
170 |
171 | @media screen and (min-width: 541px) {
172 | .mix,
173 | .gap {
174 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
175 | }
176 | }
177 |
178 | /* 4 Columns */
179 |
180 | @media screen and (min-width: 961px) {
181 | .mix,
182 | .gap {
183 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
184 | }
185 | }
186 |
187 | /* 5 Columns */
188 |
189 | @media screen and (min-width: 1281px) {
190 | .mix,
191 | .gap {
192 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
193 | }
194 | }
195 |
196 |
197 |
--------------------------------------------------------------------------------
/demos/loading-animation/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background: #f2f2f2;
5 | }
6 |
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | /* Controls
14 | ---------------------------------------------------------------------- */
15 |
16 | .controls {
17 | padding: 1rem;
18 | background: #333;
19 | font-size: 0.1px;
20 | }
21 |
22 | .control {
23 | position: relative;
24 | display: inline-block;
25 | width: 2.7rem;
26 | height: 2.7rem;
27 | background: #444;
28 | cursor: pointer;
29 | font-size: 0.1px;
30 | color: white;
31 | transition: background 150ms;
32 | }
33 |
34 | .control:hover {
35 | background: #3f3f3f;
36 | }
37 |
38 | .control[data-filter]:after {
39 | content: '';
40 | position: absolute;
41 | width: 10px;
42 | height: 10px;
43 | top: calc(50% - 6px);
44 | left: calc(50% - 6px);
45 | border: 2px solid currentColor;
46 | border-radius: 2px;
47 | background: currentColor;
48 | transition: background-color 150ms, border-color 150ms;
49 | }
50 |
51 | .control[data-sort]:after {
52 | content: '';
53 | position: absolute;
54 | width: 10px;
55 | height: 10px;
56 | border-top: 2px solid;
57 | border-left: 2px solid;
58 | top: calc(50% - 6px);
59 | left: calc(50% - 6px);
60 | transform: translateY(1px) rotate(45deg);
61 | }
62 |
63 | .control[data-sort*=":desc"]:after {
64 | transform: translateY(-4px) rotate(-135deg);
65 | }
66 |
67 | .mixitup-control-active {
68 | background: #393939;
69 | }
70 |
71 | .mixitup-control-active[data-filter]:after {
72 | background: transparent;
73 | }
74 |
75 | .control:first-of-type {
76 | border-radius: 3px 0 0 3px;
77 | }
78 |
79 | .control:last-of-type {
80 | border-radius: 0 3px 3px 0;
81 | }
82 |
83 | .control[data-filter] + .control[data-sort] {
84 | margin-left: .75rem;
85 | }
86 |
87 | .control[data-filter=".green"] {
88 | color: #91e6c7;
89 | }
90 |
91 | .control[data-filter=".blue"] {
92 | color: #5ecdde;
93 | }
94 |
95 | .control[data-filter=".pink"] {
96 | color: #d595aa;
97 | }
98 |
99 | .control[data-filter="none"] {
100 | color: #2f2f2f;
101 | }
102 |
103 | /* Container
104 | ---------------------------------------------------------------------- */
105 |
106 | .container {
107 | padding: 1rem;
108 | text-align: justify;
109 | font-size: 0.1px;
110 | }
111 |
112 | .container:after {
113 | content: '';
114 | display: inline-block;
115 | width: 100%;
116 | }
117 |
118 | /* Target Elements
119 | ---------------------------------------------------------------------- */
120 |
121 | .mix,
122 | .gap {
123 | display: inline-block;
124 | vertical-align: top;
125 | }
126 |
127 | .mix {
128 | background: #fff;
129 | border-top: .5rem solid currentColor;
130 | border-radius: 2px;
131 | margin-bottom: 1rem;
132 | position: relative;
133 | }
134 |
135 | .mix:before {
136 | content: '';
137 | display: inline-block;
138 | padding-top: 56.25%;
139 | }
140 |
141 | .mix.green {
142 | color: #91e6c7;
143 | }
144 |
145 | .mix.pink {
146 | color: #d595aa;
147 | }
148 |
149 | .mix.blue {
150 | color: #5ecdde;
151 | }
152 |
153 | .mix {
154 | visibility: hidden;
155 | }
156 |
157 | .mixitup-ready .mix {
158 | visibility: visible;
159 | }
160 |
161 | /* Grid Breakpoints
162 | ---------------------------------------------------------------------- */
163 |
164 | /* 2 Columns */
165 |
166 | .mix,
167 | .gap {
168 | width: calc(100%/2 - (((2 - 1) * 1rem) / 2));
169 | }
170 |
171 | /* 3 Columns */
172 |
173 | @media screen and (min-width: 541px) {
174 | .mix,
175 | .gap {
176 | width: calc(100%/3 - (((3 - 1) * 1rem) / 3));
177 | }
178 | }
179 |
180 | /* 4 Columns */
181 |
182 | @media screen and (min-width: 961px) {
183 | .mix,
184 | .gap {
185 | width: calc(100%/4 - (((4 - 1) * 1rem) / 4));
186 | }
187 | }
188 |
189 | /* 5 Columns */
190 |
191 | @media screen and (min-width: 1281px) {
192 | .mix,
193 | .gap {
194 | width: calc(100%/5 - (((5 - 1) * 1rem) / 5));
195 | }
196 | }
197 |
198 |
199 |
--------------------------------------------------------------------------------