mixitup-rails 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8ff48b092c8ba5b9cf5d3e8f113d9a2e2a64aa111febb439c607558c98c81771
4
+ data.tar.gz: f6444ec6974d53df71e2efb7110b24ff0d68c3025c256e9549bbc856112604c4
5
+ SHA512:
6
+ metadata.gz: 3a465556a02aa7f8e3731b85843b23f7a74d8ba8759b1d98ce78b51f3b60a0bdb853fe6bddb0d908e85769f66c7a8daec0eb58d67f405fdf0fe559a5bf6c7d14
7
+ data.tar.gz: cf4550788106f62390fcb626508daa5362725469d50279c78dcb50e20e27cf6d46eddb8235c68060d5cd703c5eefeb0532f73d0e6034f88563c9f691998987b8
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Ilya Bodrov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # MixItUpRails
2
+
3
+ A ruby gem that uses the Rails asset pipeline to include the [MixItUp JavaScript library by Kunkka labs](https://www.kunkalabs.com/mixitup).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "mixitup-rails"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```console
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```console
22
+ $ gem install mixitup-rails
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ Add this line into your `application.js`:
28
+
29
+ ```js
30
+ //= require mixitup
31
+ ```
32
+
33
+ ## Testing
34
+
35
+ Run
36
+
37
+ ```console
38
+ $ bundle install
39
+ ```
40
+
41
+ and then
42
+
43
+ ```console
44
+ $ rake test
45
+ ```
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork it
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
51
+ 3. Make sure tests are passing
52
+ 4. Commit your changes (`git commit -am 'Added some feature'`)
53
+ 5. Push to the branch (`git push origin my-new-feature`)
54
+ 6. Create new Pull Request
55
+
56
+ ## License
57
+
58
+ This plugin is licensed under the [MIT License](https://github.com/bodrovis/mixitup-rails/blob/master/LICENSE.txt).
59
+
60
+ Copyright (c) 2019 [Ilya Bodrov](http://bodrovis.tech)
@@ -0,0 +1,10682 @@
1
+ /**!
2
+ * MixItUp v3.3.1
3
+ * A high-performance, dependency-free library for animated filtering, sorting and more
4
+ * Build 94e0fbf6-cd0b-4987-b3c0-14b59b67b8a0
5
+ *
6
+ * @copyright Copyright 2014-2018 KunkaLabs Limited.
7
+ * @author KunkaLabs Limited.
8
+ * @link https://www.kunkalabs.com/mixitup/
9
+ *
10
+ * @license Commercial use requires a commercial license.
11
+ * https://www.kunkalabs.com/mixitup/licenses/
12
+ *
13
+ * Non-commercial use permitted under same terms as CC BY-NC 3.0 license.
14
+ * http://creativecommons.org/licenses/by-nc/3.0/
15
+ */
16
+
17
+ (function(window) {
18
+ 'use strict';
19
+
20
+ var mixitup = null,
21
+ h = null;
22
+
23
+ (function() {
24
+ var VENDORS = ['webkit', 'moz', 'o', 'ms'],
25
+ canary = window.document.createElement('div'),
26
+ i = -1;
27
+
28
+ // window.requestAnimationFrame
29
+
30
+ for (i = 0; i < VENDORS.length && !window.requestAnimationFrame; i++) {
31
+ window.requestAnimationFrame = window[VENDORS[i] + 'RequestAnimationFrame'];
32
+ }
33
+
34
+ // Element.nextElementSibling
35
+
36
+ if (typeof canary.nextElementSibling === 'undefined') {
37
+ Object.defineProperty(window.Element.prototype, 'nextElementSibling', {
38
+ get: function() {
39
+ var el = this.nextSibling;
40
+
41
+ while (el) {
42
+ if (el.nodeType === 1) {
43
+ return el;
44
+ }
45
+
46
+ el = el.nextSibling;
47
+ }
48
+
49
+ return null;
50
+ }
51
+ });
52
+ }
53
+
54
+ // Element.matches
55
+
56
+ (function(ElementPrototype) {
57
+ ElementPrototype.matches =
58
+ ElementPrototype.matches ||
59
+ ElementPrototype.machesSelector ||
60
+ ElementPrototype.mozMatchesSelector ||
61
+ ElementPrototype.msMatchesSelector ||
62
+ ElementPrototype.oMatchesSelector ||
63
+ ElementPrototype.webkitMatchesSelector ||
64
+ function (selector) {
65
+ return Array.prototype.indexOf.call(this.parentElement.querySelectorAll(selector), this) > -1;
66
+ };
67
+ })(window.Element.prototype);
68
+
69
+ // Object.keys
70
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
71
+
72
+ if (!Object.keys) {
73
+ Object.keys = (function() {
74
+ var hasOwnProperty = Object.prototype.hasOwnProperty,
75
+ hasDontEnumBug = false,
76
+ dontEnums = [],
77
+ dontEnumsLength = -1;
78
+
79
+ hasDontEnumBug = !({
80
+ toString: null
81
+ })
82
+ .propertyIsEnumerable('toString');
83
+
84
+ dontEnums = [
85
+ 'toString',
86
+ 'toLocaleString',
87
+ 'valueOf',
88
+ 'hasOwnProperty',
89
+ 'isPrototypeOf',
90
+ 'propertyIsEnumerable',
91
+ 'constructor'
92
+ ];
93
+
94
+ dontEnumsLength = dontEnums.length;
95
+
96
+ return function(obj) {
97
+ var result = [],
98
+ prop = '',
99
+ i = -1;
100
+
101
+ if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
102
+ throw new TypeError('Object.keys called on non-object');
103
+ }
104
+
105
+ for (prop in obj) {
106
+ if (hasOwnProperty.call(obj, prop)) {
107
+ result.push(prop);
108
+ }
109
+ }
110
+
111
+ if (hasDontEnumBug) {
112
+ for (i = 0; i < dontEnumsLength; i++) {
113
+ if (hasOwnProperty.call(obj, dontEnums[i])) {
114
+ result.push(dontEnums[i]);
115
+ }
116
+ }
117
+ }
118
+
119
+ return result;
120
+ };
121
+ }());
122
+ }
123
+
124
+ // Array.isArray
125
+ // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
126
+
127
+ if (!Array.isArray) {
128
+ Array.isArray = function(arg) {
129
+ return Object.prototype.toString.call(arg) === '[object Array]';
130
+ };
131
+ }
132
+
133
+ // Object.create
134
+ // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create
135
+
136
+ if (typeof Object.create !== 'function') {
137
+ Object.create = (function(undefined) {
138
+ var Temp = function() {};
139
+
140
+ return function (prototype, propertiesObject) {
141
+ if (prototype !== Object(prototype) && prototype !== null) {
142
+ throw TypeError('Argument must be an object, or null');
143
+ }
144
+
145
+ Temp.prototype = prototype || {};
146
+
147
+ var result = new Temp();
148
+
149
+ Temp.prototype = null;
150
+
151
+ if (propertiesObject !== undefined) {
152
+ Object.defineProperties(result, propertiesObject);
153
+ }
154
+
155
+ if (prototype === null) {
156
+ /* jshint ignore:start */
157
+ result.__proto__ = null;
158
+ /* jshint ignore:end */
159
+ }
160
+
161
+ return result;
162
+ };
163
+ })();
164
+ }
165
+
166
+ // String.prototyoe.trim
167
+
168
+ if (!String.prototype.trim) {
169
+ String.prototype.trim = function() {
170
+ return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
171
+ };
172
+ }
173
+
174
+ // Array.prototype.indexOf
175
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
176
+
177
+ if (!Array.prototype.indexOf) {
178
+ Array.prototype.indexOf = function(searchElement) {
179
+ var n, k, t, len;
180
+
181
+ if (this === null) {
182
+ throw new TypeError();
183
+ }
184
+
185
+ t = Object(this);
186
+
187
+ len = t.length >>> 0;
188
+
189
+ if (len === 0) {
190
+ return -1;
191
+ }
192
+
193
+ n = 0;
194
+
195
+ if (arguments.length > 1) {
196
+ n = Number(arguments[1]);
197
+
198
+ if (n !== n) {
199
+ n = 0;
200
+ } else if (n !== 0 && n !== Infinity && n !== -Infinity) {
201
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
202
+ }
203
+ }
204
+
205
+ if (n >= len) {
206
+ return -1;
207
+ }
208
+
209
+ for (k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); k < len; k++) {
210
+ if (k in t && t[k] === searchElement) {
211
+ return k;
212
+ }
213
+ }
214
+
215
+ return -1;
216
+ };
217
+ }
218
+
219
+ // Function.prototype.bind
220
+ // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
221
+
222
+ if (!Function.prototype.bind) {
223
+ Function.prototype.bind = function(oThis) {
224
+ var aArgs, self, FNOP, fBound;
225
+
226
+ if (typeof this !== 'function') {
227
+ throw new TypeError();
228
+ }
229
+
230
+ aArgs = Array.prototype.slice.call(arguments, 1);
231
+
232
+ self = this;
233
+
234
+ FNOP = function() {};
235
+
236
+ fBound = function() {
237
+ return self.apply(this instanceof FNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
238
+ };
239
+
240
+ if (this.prototype) {
241
+ FNOP.prototype = this.prototype;
242
+ }
243
+
244
+ fBound.prototype = new FNOP();
245
+
246
+ return fBound;
247
+ };
248
+ }
249
+
250
+ // Element.prototype.dispatchEvent
251
+
252
+ if (!window.Element.prototype.dispatchEvent) {
253
+ window.Element.prototype.dispatchEvent = function(event) {
254
+ try {
255
+ return this.fireEvent('on' + event.type, event);
256
+ } catch (err) {}
257
+ };
258
+ }
259
+ })();
260
+
261
+ /**
262
+ * The `mixitup()` "factory" function creates and returns individual instances
263
+ * of MixItUp, known as "mixers", on which API methods can be called.
264
+ *
265
+ * When loading MixItUp via a script tag, the factory function is accessed
266
+ * via the global variable `mixitup`. When using a module loading
267
+ * system (e.g. ES2015, CommonJS, RequireJS), the factory function is
268
+ * exported into your module when you require the MixItUp library.
269
+ *
270
+ * @example
271
+ * mixitup(container [,config] [,foreignDoc])
272
+ *
273
+ * @example <caption>Example 1: Creating a mixer instance with an element reference</caption>
274
+ * var containerEl = document.querySelector('.container');
275
+ *
276
+ * var mixer = mixitup(containerEl);
277
+ *
278
+ * @example <caption>Example 2: Creating a mixer instance with a selector string</caption>
279
+ * var mixer = mixitup('.container');
280
+ *
281
+ * @example <caption>Example 3: Passing a configuration object</caption>
282
+ * var mixer = mixitup(containerEl, {
283
+ * animation: {
284
+ * effects: 'fade scale(0.5)'
285
+ * }
286
+ * });
287
+ *
288
+ * @example <caption>Example 4: Passing an iframe reference</caption>
289
+ * var mixer = mixitup(containerEl, config, foreignDocument);
290
+ *
291
+ * @global
292
+ * @namespace
293
+ * @public
294
+ * @kind function
295
+ * @since 3.0.0
296
+ * @param {(Element|string)} container
297
+ * A DOM element or selector string representing the container(s) on which to instantiate MixItUp.
298
+ * @param {object} [config]
299
+ * An optional "configuration object" used to customize the behavior of the MixItUp instance.
300
+ * @param {object} [foreignDoc]
301
+ * An optional reference to a `document`, which can be used to control a MixItUp instance in an iframe.
302
+ * @return {mixitup.Mixer}
303
+ * A "mixer" object holding the MixItUp instance.
304
+ */
305
+
306
+ mixitup = function(container, config, foreignDoc) {
307
+ var el = null,
308
+ returnCollection = false,
309
+ instance = null,
310
+ facade = null,
311
+ doc = null,
312
+ output = null,
313
+ instances = [],
314
+ id = '',
315
+ elements = [],
316
+ i = -1;
317
+
318
+ doc = foreignDoc || window.document;
319
+
320
+ if (returnCollection = arguments[3]) {
321
+ // A non-documented 4th paramater enabling control of multiple instances
322
+
323
+ returnCollection = typeof returnCollection === 'boolean';
324
+ }
325
+
326
+ if (typeof container === 'string') {
327
+ elements = doc.querySelectorAll(container);
328
+ } else if (container && typeof container === 'object' && h.isElement(container, doc)) {
329
+ elements = [container];
330
+ } else if (container && typeof container === 'object' && container.length) {
331
+ // Although not documented, the container may also be an array-like list of
332
+ // elements such as a NodeList or jQuery collection, is returnCollection is true
333
+
334
+ elements = container;
335
+ } else {
336
+ throw new Error(mixitup.messages.errorFactoryInvalidContainer());
337
+ }
338
+
339
+ if (elements.length < 1) {
340
+ throw new Error(mixitup.messages.errorFactoryContainerNotFound());
341
+ }
342
+
343
+ for (i = 0; el = elements[i]; i++) {
344
+ if (i > 0 && !returnCollection) break;
345
+
346
+ if (!el.id) {
347
+ id = 'MixItUp' + h.randomHex();
348
+
349
+ el.id = id;
350
+ } else {
351
+ id = el.id;
352
+ }
353
+
354
+ if (mixitup.instances[id] instanceof mixitup.Mixer) {
355
+ instance = mixitup.instances[id];
356
+
357
+ if (!config || (config && config.debug && config.debug.showWarnings !== false)) {
358
+ console.warn(mixitup.messages.warningFactoryPreexistingInstance());
359
+ }
360
+ } else {
361
+ instance = new mixitup.Mixer();
362
+
363
+ instance.attach(el, doc, id, config);
364
+
365
+ mixitup.instances[id] = instance;
366
+ }
367
+
368
+ facade = new mixitup.Facade(instance);
369
+
370
+ if (config && config.debug && config.debug.enable) {
371
+ instances.push(instance);
372
+ } else {
373
+ instances.push(facade);
374
+ }
375
+ }
376
+
377
+ if (returnCollection) {
378
+ output = new mixitup.Collection(instances);
379
+ } else {
380
+ // Return the first instance regardless
381
+
382
+ output = instances[0];
383
+ }
384
+
385
+ return output;
386
+ };
387
+
388
+ /**
389
+ * The `.use()` static method is used to extend the functionality of mixitup with compatible
390
+ * extensions and libraries in an environment with modular scoping e.g. ES2015, CommonJS, or RequireJS.
391
+ *
392
+ * You need only call the `.use()` function once per project, per extension, as module loaders
393
+ * will cache a single reference to MixItUp inclusive of all changes made.
394
+ *
395
+ * @example
396
+ * mixitup.use(extension)
397
+ *
398
+ * @example <caption>Example 1: Extending MixItUp with the Pagination Extension</caption>
399
+ *
400
+ * import mixitup from 'mixitup';
401
+ * import mixitupPagination from 'mixitup-pagination';
402
+ *
403
+ * mixitup.use(mixitupPagination);
404
+ *
405
+ * // All mixers created by the factory function in all modules will now
406
+ * // have pagination functionality
407
+ *
408
+ * var mixer = mixitup('.container');
409
+ *
410
+ * @public
411
+ * @name use
412
+ * @memberof mixitup
413
+ * @kind function
414
+ * @static
415
+ * @since 3.0.0
416
+ * @param {*} extension A reference to the extension or library to be used.
417
+ * @return {void}
418
+ */
419
+
420
+ mixitup.use = function(extension) {
421
+ mixitup.Base.prototype.callActions.call(mixitup, 'beforeUse', arguments);
422
+
423
+ // Call the extension's factory function, passing
424
+ // the mixitup factory as a paramater
425
+
426
+ if (typeof extension === 'function' && extension.TYPE === 'mixitup-extension') {
427
+ // Mixitup extension
428
+
429
+ if (typeof mixitup.extensions[extension.NAME] === 'undefined') {
430
+ extension(mixitup);
431
+
432
+ mixitup.extensions[extension.NAME] = extension;
433
+ }
434
+ } else if (extension.fn && extension.fn.jquery) {
435
+ // jQuery
436
+
437
+ mixitup.libraries.$ = extension;
438
+ }
439
+
440
+ mixitup.Base.prototype.callActions.call(mixitup, 'afterUse', arguments);
441
+ };
442
+
443
+ mixitup.instances = {};
444
+ mixitup.extensions = {};
445
+ mixitup.libraries = {};
446
+
447
+ /**
448
+ * @private
449
+ */
450
+
451
+ h = {
452
+
453
+ /**
454
+ * @private
455
+ * @param {HTMLElement} el
456
+ * @param {string} cls
457
+ * @return {boolean}
458
+ */
459
+
460
+ hasClass: function(el, cls) {
461
+ return !!el.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
462
+ },
463
+
464
+ /**
465
+ * @private
466
+ * @param {HTMLElement} el
467
+ * @param {string} cls
468
+ * @return {void}
469
+ */
470
+
471
+ addClass: function(el, cls) {
472
+ if (!this.hasClass(el, cls)) el.className += el.className ? ' ' + cls : cls;
473
+ },
474
+
475
+ /**
476
+ * @private
477
+ * @param {HTMLElement} el
478
+ * @param {string} cls
479
+ * @return {void}
480
+ */
481
+
482
+ removeClass: function(el, cls) {
483
+ if (this.hasClass(el, cls)) {
484
+ var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
485
+
486
+ el.className = el.className.replace(reg, ' ').trim();
487
+ }
488
+ },
489
+
490
+ /**
491
+ * Merges the properties of the source object onto the
492
+ * target object. Alters the target object.
493
+ *
494
+ * @private
495
+ * @param {object} destination
496
+ * @param {object} source
497
+ * @param {boolean} [deep=false]
498
+ * @param {boolean} [handleErrors=false]
499
+ * @return {void}
500
+ */
501
+
502
+ extend: function(destination, source, deep, handleErrors) {
503
+ var sourceKeys = [],
504
+ key = '',
505
+ i = -1;
506
+
507
+ deep = deep || false;
508
+ handleErrors = handleErrors || false;
509
+
510
+ try {
511
+ if (Array.isArray(source)) {
512
+ for (i = 0; i < source.length; i++) {
513
+ sourceKeys.push(i);
514
+ }
515
+ } else if (source) {
516
+ sourceKeys = Object.keys(source);
517
+ }
518
+
519
+ for (i = 0; i < sourceKeys.length; i++) {
520
+ key = sourceKeys[i];
521
+
522
+ if (!deep || typeof source[key] !== 'object' || this.isElement(source[key])) {
523
+ // All non-object properties, or all properties if shallow extend
524
+
525
+ destination[key] = source[key];
526
+ } else if (Array.isArray(source[key])) {
527
+ // Arrays
528
+
529
+ if (!destination[key]) {
530
+ destination[key] = [];
531
+ }
532
+
533
+ this.extend(destination[key], source[key], deep, handleErrors);
534
+ } else {
535
+ // Objects
536
+
537
+ if (!destination[key]) {
538
+ destination[key] = {};
539
+ }
540
+
541
+ this.extend(destination[key], source[key], deep, handleErrors);
542
+ }
543
+ }
544
+ } catch(err) {
545
+ if (handleErrors) {
546
+ this.handleExtendError(err, destination);
547
+ } else {
548
+ throw err;
549
+ }
550
+ }
551
+
552
+ return destination;
553
+ },
554
+
555
+ /**
556
+ * @private
557
+ * @param {Error} err
558
+ * @param {object} destination
559
+ * @return {void}
560
+ */
561
+
562
+ handleExtendError: function(err, destination) {
563
+ var re = /property "?(\w*)"?[,:] object/i,
564
+ matches = null,
565
+ erroneous = '',
566
+ message = '',
567
+ suggestion = '',
568
+ probableMatch = '',
569
+ key = '',
570
+ mostMatchingChars = -1,
571
+ i = -1;
572
+
573
+ if (err instanceof TypeError && (matches = re.exec(err.message))) {
574
+ erroneous = matches[1];
575
+
576
+ for (key in destination) {
577
+ i = 0;
578
+
579
+ while (i < erroneous.length && erroneous.charAt(i) === key.charAt(i)) {
580
+ i++;
581
+ }
582
+
583
+ if (i > mostMatchingChars) {
584
+ mostMatchingChars = i;
585
+ probableMatch = key;
586
+ }
587
+ }
588
+
589
+ if (mostMatchingChars > 1) {
590
+ suggestion = mixitup.messages.errorConfigInvalidPropertySuggestion({
591
+ probableMatch: probableMatch
592
+ });
593
+ }
594
+
595
+ message = mixitup.messages.errorConfigInvalidProperty({
596
+ erroneous: erroneous,
597
+ suggestion: suggestion
598
+ });
599
+
600
+ throw new TypeError(message);
601
+ }
602
+
603
+ throw err;
604
+ },
605
+
606
+ /**
607
+ * @private
608
+ * @param {string} str
609
+ * @return {function}
610
+ */
611
+
612
+ template: function(str) {
613
+ var re = /\${([\w]*)}/g,
614
+ dynamics = {},
615
+ matches = null;
616
+
617
+ while ((matches = re.exec(str))) {
618
+ dynamics[matches[1]] = new RegExp('\\${' + matches[1] + '}', 'g');
619
+ }
620
+
621
+ return function(data) {
622
+ var key = '',
623
+ output = str;
624
+
625
+ data = data || {};
626
+
627
+ for (key in dynamics) {
628
+ output = output.replace(dynamics[key], typeof data[key] !== 'undefined' ? data[key] : '');
629
+ }
630
+
631
+ return output;
632
+ };
633
+ },
634
+
635
+ /**
636
+ * @private
637
+ * @param {HTMLElement} el
638
+ * @param {string} type
639
+ * @param {function} fn
640
+ * @param {boolean} useCapture
641
+ * @return {void}
642
+ */
643
+
644
+ on: function(el, type, fn, useCapture) {
645
+ if (!el) return;
646
+
647
+ if (el.addEventListener) {
648
+ el.addEventListener(type, fn, useCapture);
649
+ } else if (el.attachEvent) {
650
+ el['e' + type + fn] = fn;
651
+
652
+ el[type + fn] = function() {
653
+ el['e' + type + fn](window.event);
654
+ };
655
+
656
+ el.attachEvent('on' + type, el[type + fn]);
657
+ }
658
+ },
659
+
660
+ /**
661
+ * @private
662
+ * @param {HTMLElement} el
663
+ * @param {string} type
664
+ * @param {function} fn
665
+ * @return {void}
666
+ */
667
+
668
+ off: function(el, type, fn) {
669
+ if (!el) return;
670
+
671
+ if (el.removeEventListener) {
672
+ el.removeEventListener(type, fn, false);
673
+ } else if (el.detachEvent) {
674
+ el.detachEvent('on' + type, el[type + fn]);
675
+ el[type + fn] = null;
676
+ }
677
+ },
678
+
679
+ /**
680
+ * @private
681
+ * @param {string} eventType
682
+ * @param {object} detail
683
+ * @param {Document} [doc]
684
+ * @return {CustomEvent}
685
+ */
686
+
687
+ getCustomEvent: function(eventType, detail, doc) {
688
+ var event = null;
689
+
690
+ doc = doc || window.document;
691
+
692
+ if (typeof window.CustomEvent === 'function') {
693
+ event = new window.CustomEvent(eventType, {
694
+ detail: detail,
695
+ bubbles: true,
696
+ cancelable: true
697
+ });
698
+ } else if (typeof doc.createEvent === 'function') {
699
+ event = doc.createEvent('CustomEvent');
700
+ event.initCustomEvent(eventType, true, true, detail);
701
+ } else {
702
+ event = doc.createEventObject(),
703
+ event.type = eventType;
704
+
705
+ event.returnValue = false;
706
+ event.cancelBubble = false;
707
+ event.detail = detail;
708
+ }
709
+
710
+ return event;
711
+ },
712
+
713
+ /**
714
+ * @private
715
+ * @param {Event} e
716
+ * @return {Event}
717
+ */
718
+
719
+ getOriginalEvent: function(e) {
720
+ if (e.touches && e.touches.length) {
721
+ return e.touches[0];
722
+ } else if (e.changedTouches && e.changedTouches.length) {
723
+ return e.changedTouches[0];
724
+ } else {
725
+ return e;
726
+ }
727
+ },
728
+
729
+ /**
730
+ * @private
731
+ * @param {HTMLElement} el
732
+ * @param {string} selector
733
+ * @return {Number}
734
+ */
735
+
736
+ index: function(el, selector) {
737
+ var i = 0;
738
+
739
+ while ((el = el.previousElementSibling) !== null) {
740
+ if (!selector || el.matches(selector)) {
741
+ ++i;
742
+ }
743
+ }
744
+
745
+ return i;
746
+ },
747
+
748
+ /**
749
+ * Converts a dash or snake-case string to camel case.
750
+ *
751
+ * @private
752
+ * @param {string} str
753
+ * @param {boolean} [isPascal]
754
+ * @return {string}
755
+ */
756
+
757
+ camelCase: function(str) {
758
+ return str.toLowerCase().replace(/([_-][a-z])/g, function($1) {
759
+ return $1.toUpperCase().replace(/[_-]/, '');
760
+ });
761
+ },
762
+
763
+ /**
764
+ * Converts a dash or snake-case string to pascal case.
765
+ *
766
+ * @private
767
+ * @param {string} str
768
+ * @param {boolean} [isPascal]
769
+ * @return {string}
770
+ */
771
+
772
+ pascalCase: function(str) {
773
+ return (str = this.camelCase(str)).charAt(0).toUpperCase() + str.slice(1);
774
+ },
775
+
776
+ /**
777
+ * Converts a camel or pascal-case string to dash case.
778
+ *
779
+ * @private
780
+ * @param {string} str
781
+ * @return {string}
782
+ */
783
+
784
+ dashCase: function(str) {
785
+ return str.replace(/([A-Z])/g, '-$1').replace(/^-/, '').toLowerCase();
786
+ },
787
+
788
+ /**
789
+ * @private
790
+ * @param {HTMLElement} el
791
+ * @param {HTMLHtmlElement} [doc]
792
+ * @return {boolean}
793
+ */
794
+
795
+ isElement: function(el, doc) {
796
+ doc = doc || window.document;
797
+
798
+ if (
799
+ window.HTMLElement &&
800
+ el instanceof window.HTMLElement
801
+ ) {
802
+ return true;
803
+ } else if (
804
+ doc.defaultView &&
805
+ doc.defaultView.HTMLElement &&
806
+ el instanceof doc.defaultView.HTMLElement
807
+ ) {
808
+ return true;
809
+ } else {
810
+ return (
811
+ el !== null &&
812
+ el.nodeType === 1 &&
813
+ typeof el.nodeName === 'string'
814
+ );
815
+ }
816
+ },
817
+
818
+ /**
819
+ * @private
820
+ * @param {string} htmlString
821
+ * @param {HTMLHtmlElement} [doc]
822
+ * @return {DocumentFragment}
823
+ */
824
+
825
+ createElement: function(htmlString, doc) {
826
+ var frag = null,
827
+ temp = null;
828
+
829
+ doc = doc || window.document;
830
+
831
+ frag = doc.createDocumentFragment();
832
+ temp = doc.createElement('div');
833
+
834
+ temp.innerHTML = htmlString.trim();
835
+
836
+ while (temp.firstChild) {
837
+ frag.appendChild(temp.firstChild);
838
+ }
839
+
840
+ return frag;
841
+ },
842
+
843
+ /**
844
+ * @private
845
+ * @param {Node} node
846
+ * @return {void}
847
+ */
848
+
849
+ removeWhitespace: function(node) {
850
+ var deleting;
851
+
852
+ while (node && node.nodeName === '#text') {
853
+ deleting = node;
854
+
855
+ node = node.previousSibling;
856
+
857
+ deleting.parentElement && deleting.parentElement.removeChild(deleting);
858
+ }
859
+ },
860
+
861
+ /**
862
+ * @private
863
+ * @param {Array<*>} a
864
+ * @param {Array<*>} b
865
+ * @return {boolean}
866
+ */
867
+
868
+ isEqualArray: function(a, b) {
869
+ var i = a.length;
870
+
871
+ if (i !== b.length) return false;
872
+
873
+ while (i--) {
874
+ if (a[i] !== b[i]) return false;
875
+ }
876
+
877
+ return true;
878
+ },
879
+
880
+ /**
881
+ * @private
882
+ * @param {object} a
883
+ * @param {object} b
884
+ * @return {boolean}
885
+ */
886
+
887
+ deepEquals: function(a, b) {
888
+ var key;
889
+
890
+ if (typeof a === 'object' && a && typeof b === 'object' && b) {
891
+ if (Object.keys(a).length !== Object.keys(b).length) return false;
892
+
893
+ for (key in a) {
894
+ if (!b.hasOwnProperty(key) || !this.deepEquals(a[key], b[key])) return false;
895
+ }
896
+ } else if (a !== b) {
897
+ return false;
898
+ }
899
+
900
+ return true;
901
+ },
902
+
903
+ /**
904
+ * @private
905
+ * @param {Array<*>} oldArray
906
+ * @return {Array<*>}
907
+ */
908
+
909
+ arrayShuffle: function(oldArray) {
910
+ var newArray = oldArray.slice(),
911
+ len = newArray.length,
912
+ i = len,
913
+ p = -1,
914
+ t = [];
915
+
916
+ while (i--) {
917
+ p = ~~(Math.random() * len);
918
+ t = newArray[i];
919
+
920
+ newArray[i] = newArray[p];
921
+ newArray[p] = t;
922
+ }
923
+
924
+ return newArray;
925
+ },
926
+
927
+ /**
928
+ * @private
929
+ * @param {object} list
930
+ */
931
+
932
+ arrayFromList: function(list) {
933
+ var output, i;
934
+
935
+ try {
936
+ return Array.prototype.slice.call(list);
937
+ } catch(err) {
938
+ output = [];
939
+
940
+ for (i = 0; i < list.length; i++) {
941
+ output.push(list[i]);
942
+ }
943
+
944
+ return output;
945
+ }
946
+ },
947
+
948
+ /**
949
+ * @private
950
+ * @param {function} func
951
+ * @param {Number} wait
952
+ * @param {boolean} immediate
953
+ * @return {function}
954
+ */
955
+
956
+ debounce: function(func, wait, immediate) {
957
+ var timeout;
958
+
959
+ return function() {
960
+ var self = this,
961
+ args = arguments,
962
+ callNow = immediate && !timeout,
963
+ later = null;
964
+
965
+ later = function() {
966
+ timeout = null;
967
+
968
+ if (!immediate) {
969
+ func.apply(self, args);
970
+ }
971
+ };
972
+
973
+ clearTimeout(timeout);
974
+
975
+ timeout = setTimeout(later, wait);
976
+
977
+ if (callNow) func.apply(self, args);
978
+ };
979
+ },
980
+
981
+ /**
982
+ * @private
983
+ * @param {HTMLElement} element
984
+ * @return {object}
985
+ */
986
+
987
+ position: function(element) {
988
+ var xPosition = 0,
989
+ yPosition = 0,
990
+ offsetParent = element;
991
+
992
+ while (element) {
993
+ xPosition -= element.scrollLeft;
994
+ yPosition -= element.scrollTop;
995
+
996
+ if (element === offsetParent) {
997
+ xPosition += element.offsetLeft;
998
+ yPosition += element.offsetTop;
999
+
1000
+ offsetParent = element.offsetParent;
1001
+ }
1002
+
1003
+ element = element.parentElement;
1004
+ }
1005
+
1006
+ return {
1007
+ x: xPosition,
1008
+ y: yPosition
1009
+ };
1010
+ },
1011
+
1012
+ /**
1013
+ * @private
1014
+ * @param {object} node1
1015
+ * @param {object} node2
1016
+ * @return {Number}
1017
+ */
1018
+
1019
+ getHypotenuse: function(node1, node2) {
1020
+ var distanceX = node1.x - node2.x,
1021
+ distanceY = node1.y - node2.y;
1022
+
1023
+ distanceX = distanceX < 0 ? distanceX * -1 : distanceX,
1024
+ distanceY = distanceY < 0 ? distanceY * -1 : distanceY;
1025
+
1026
+ return Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));
1027
+ },
1028
+
1029
+ /**
1030
+ * Calcuates the area of intersection between two rectangles and expresses it as
1031
+ * a ratio in comparison to the area of the first rectangle.
1032
+ *
1033
+ * @private
1034
+ * @param {Rect} box1
1035
+ * @param {Rect} box2
1036
+ * @return {number}
1037
+ */
1038
+
1039
+ getIntersectionRatio: function(box1, box2) {
1040
+ var controlArea = box1.width * box1.height,
1041
+ intersectionX = -1,
1042
+ intersectionY = -1,
1043
+ intersectionArea = -1,
1044
+ ratio = -1;
1045
+
1046
+ intersectionX =
1047
+ Math.max(0, Math.min(box1.left + box1.width, box2.left + box2.width) - Math.max(box1.left, box2.left));
1048
+
1049
+ intersectionY =
1050
+ Math.max(0, Math.min(box1.top + box1.height, box2.top + box2.height) - Math.max(box1.top, box2.top));
1051
+
1052
+ intersectionArea = intersectionY * intersectionX;
1053
+
1054
+ ratio = intersectionArea / controlArea;
1055
+
1056
+ return ratio;
1057
+ },
1058
+
1059
+ /**
1060
+ * @private
1061
+ * @param {object} el
1062
+ * @param {string} selector
1063
+ * @param {boolean} [includeSelf]
1064
+ * @param {HTMLHtmlElement} [doc]
1065
+ * @return {Element|null}
1066
+ */
1067
+
1068
+ closestParent: function(el, selector, includeSelf, doc) {
1069
+ var parent = el.parentNode;
1070
+
1071
+ doc = doc || window.document;
1072
+
1073
+ if (includeSelf && el.matches(selector)) {
1074
+ return el;
1075
+ }
1076
+
1077
+ while (parent && parent != doc.body) {
1078
+ if (parent.matches && parent.matches(selector)) {
1079
+ return parent;
1080
+ } else if (parent.parentNode) {
1081
+ parent = parent.parentNode;
1082
+ } else {
1083
+ return null;
1084
+ }
1085
+ }
1086
+
1087
+ return null;
1088
+ },
1089
+
1090
+ /**
1091
+ * @private
1092
+ * @param {HTMLElement} el
1093
+ * @param {string} selector
1094
+ * @param {HTMLHtmlElement} [doc]
1095
+ * @return {NodeList}
1096
+ */
1097
+
1098
+ children: function(el, selector, doc) {
1099
+ var children = [],
1100
+ tempId = '';
1101
+
1102
+ doc = doc || window.doc;
1103
+
1104
+ if (el) {
1105
+ if (!el.id) {
1106
+ tempId = 'Temp' + this.randomHexKey();
1107
+
1108
+ el.id = tempId;
1109
+ }
1110
+
1111
+ children = doc.querySelectorAll('#' + el.id + ' > ' + selector);
1112
+
1113
+ if (tempId) {
1114
+ el.removeAttribute('id');
1115
+ }
1116
+ }
1117
+
1118
+ return children;
1119
+ },
1120
+
1121
+ /**
1122
+ * Creates a clone of a provided array, with any empty strings removed.
1123
+ *
1124
+ * @private
1125
+ * @param {Array<*>} originalArray
1126
+ * @return {Array<*>}
1127
+ */
1128
+
1129
+ clean: function(originalArray) {
1130
+ var cleanArray = [],
1131
+ i = -1;
1132
+
1133
+ for (i = 0; i < originalArray.length; i++) {
1134
+ if (originalArray[i] !== '') {
1135
+ cleanArray.push(originalArray[i]);
1136
+ }
1137
+ }
1138
+
1139
+ return cleanArray;
1140
+ },
1141
+
1142
+ /**
1143
+ * Abstracts an ES6 promise into a q-like deferred interface for storage and deferred resolution.
1144
+ *
1145
+ * @private
1146
+ * @param {object} libraries
1147
+ * @return {h.Deferred}
1148
+ */
1149
+
1150
+ defer: function(libraries) {
1151
+ var deferred = null,
1152
+ promiseWrapper = null,
1153
+ $ = null;
1154
+
1155
+ promiseWrapper = new this.Deferred();
1156
+
1157
+ if (mixitup.features.has.promises) {
1158
+ // ES6 native promise or polyfill
1159
+
1160
+ promiseWrapper.promise = new Promise(function(resolve, reject) {
1161
+ promiseWrapper.resolve = resolve;
1162
+ promiseWrapper.reject = reject;
1163
+ });
1164
+ } else if (($ = (window.jQuery || libraries.$)) && typeof $.Deferred === 'function') {
1165
+ // jQuery
1166
+
1167
+ deferred = $.Deferred();
1168
+
1169
+ promiseWrapper.promise = deferred.promise();
1170
+ promiseWrapper.resolve = deferred.resolve;
1171
+ promiseWrapper.reject = deferred.reject;
1172
+ } else if (window.console) {
1173
+ // No implementation
1174
+
1175
+ console.warn(mixitup.messages.warningNoPromiseImplementation());
1176
+ }
1177
+
1178
+ return promiseWrapper;
1179
+ },
1180
+
1181
+ /**
1182
+ * @private
1183
+ * @param {Array<Promise>} tasks
1184
+ * @param {object} libraries
1185
+ * @return {Promise<Array>}
1186
+ */
1187
+
1188
+ all: function(tasks, libraries) {
1189
+ var $ = null;
1190
+
1191
+ if (mixitup.features.has.promises) {
1192
+ return Promise.all(tasks);
1193
+ } else if (($ = (window.jQuery || libraries.$)) && typeof $.when === 'function') {
1194
+ return $.when.apply($, tasks)
1195
+ .done(function() {
1196
+ // jQuery when returns spread arguments rather than an array or resolutions
1197
+
1198
+ return arguments;
1199
+ });
1200
+ }
1201
+
1202
+ // No implementation
1203
+
1204
+ if (window.console) {
1205
+ console.warn(mixitup.messages.warningNoPromiseImplementation());
1206
+ }
1207
+
1208
+ return [];
1209
+ },
1210
+
1211
+ /**
1212
+ * @private
1213
+ * @param {HTMLElement} el
1214
+ * @param {string} property
1215
+ * @param {Array<string>} vendors
1216
+ * @return {string}
1217
+ */
1218
+
1219
+ getPrefix: function(el, property, vendors) {
1220
+ var i = -1,
1221
+ prefix = '';
1222
+
1223
+ if (h.dashCase(property) in el.style) return '';
1224
+
1225
+ for (i = 0; prefix = vendors[i]; i++) {
1226
+ if (prefix + property in el.style) {
1227
+ return prefix.toLowerCase();
1228
+ }
1229
+ }
1230
+
1231
+ return 'unsupported';
1232
+ },
1233
+
1234
+ /**
1235
+ * @private
1236
+ * @return {string}
1237
+ */
1238
+
1239
+ randomHex: function() {
1240
+ return ('00000' + (Math.random() * 16777216 << 0).toString(16)).substr(-6).toUpperCase();
1241
+ },
1242
+
1243
+ /**
1244
+ * @private
1245
+ * @param {HTMLDocument} [doc]
1246
+ * @return {object}
1247
+ */
1248
+
1249
+ getDocumentState: function(doc) {
1250
+ doc = typeof doc.body === 'object' ? doc : window.document;
1251
+
1252
+ return {
1253
+ scrollTop: window.pageYOffset,
1254
+ scrollLeft: window.pageXOffset,
1255
+ docHeight: doc.documentElement.scrollHeight,
1256
+ docWidth: doc.documentElement.scrollWidth,
1257
+ viewportHeight: doc.documentElement.clientHeight,
1258
+ viewportWidth: doc.documentElement.clientWidth
1259
+ };
1260
+ },
1261
+
1262
+ /**
1263
+ * @private
1264
+ * @param {object} obj
1265
+ * @param {function} fn
1266
+ * @return {function}
1267
+ */
1268
+
1269
+ bind: function(obj, fn) {
1270
+ return function() {
1271
+ return fn.apply(obj, arguments);
1272
+ };
1273
+ },
1274
+
1275
+ /**
1276
+ * @private
1277
+ * @param {HTMLElement} el
1278
+ * @return {boolean}
1279
+ */
1280
+
1281
+ isVisible: function(el) {
1282
+ var styles = null;
1283
+
1284
+ if (el.offsetParent) return true;
1285
+
1286
+ styles = window.getComputedStyle(el);
1287
+
1288
+ if (
1289
+ styles.position === 'fixed' &&
1290
+ styles.visibility !== 'hidden' &&
1291
+ styles.opacity !== '0'
1292
+ ) {
1293
+ // Fixed elements report no offsetParent,
1294
+ // but may still be invisible
1295
+
1296
+ return true;
1297
+ }
1298
+
1299
+ return false;
1300
+ },
1301
+
1302
+ /**
1303
+ * @private
1304
+ * @param {object} obj
1305
+ */
1306
+
1307
+ seal: function(obj) {
1308
+ if (typeof Object.seal === 'function') {
1309
+ Object.seal(obj);
1310
+ }
1311
+ },
1312
+
1313
+ /**
1314
+ * @private
1315
+ * @param {object} obj
1316
+ */
1317
+
1318
+ freeze: function(obj) {
1319
+ if (typeof Object.freeze === 'function') {
1320
+ Object.freeze(obj);
1321
+ }
1322
+ },
1323
+
1324
+ /**
1325
+ * @private
1326
+ * @param {string} control
1327
+ * @param {string} specimen
1328
+ * @return {boolean}
1329
+ */
1330
+
1331
+ compareVersions: function(control, specimen) {
1332
+ var controlParts = control.split('.'),
1333
+ specimenParts = specimen.split('.'),
1334
+ controlPart = -1,
1335
+ specimenPart = -1,
1336
+ i = -1;
1337
+
1338
+ for (i = 0; i < controlParts.length; i++) {
1339
+ controlPart = parseInt(controlParts[i].replace(/[^\d.]/g, ''));
1340
+ specimenPart = parseInt(specimenParts[i].replace(/[^\d.]/g, '') || 0);
1341
+
1342
+ if (specimenPart < controlPart) {
1343
+ return false;
1344
+ } else if (specimenPart > controlPart) {
1345
+ return true;
1346
+ }
1347
+ }
1348
+
1349
+ return true;
1350
+ },
1351
+
1352
+ /**
1353
+ * @private
1354
+ * @constructor
1355
+ */
1356
+
1357
+ Deferred: function() {
1358
+ this.promise = null;
1359
+ this.resolve = null;
1360
+ this.reject = null;
1361
+ this.id = h.randomHex();
1362
+ },
1363
+
1364
+ /**
1365
+ * @private
1366
+ * @param {object} obj
1367
+ * @return {boolean}
1368
+ */
1369
+
1370
+ isEmptyObject: function(obj) {
1371
+ var key = '';
1372
+
1373
+ if (typeof Object.keys === 'function') {
1374
+ return Object.keys(obj).length === 0;
1375
+ }
1376
+
1377
+ for (key in obj) {
1378
+ if (obj.hasOwnProperty(key)) {
1379
+ return false;
1380
+ }
1381
+ }
1382
+
1383
+ return true;
1384
+ },
1385
+
1386
+ /**
1387
+ * @param {mixitup.Config.ClassNames} classNames
1388
+ * @param {string} elementName
1389
+ * @param {string} [modifier]
1390
+ * @return {string}
1391
+ */
1392
+
1393
+ getClassname: function(classNames, elementName, modifier) {
1394
+ var classname = '';
1395
+
1396
+ classname += classNames.block;
1397
+
1398
+ if (classname.length) {
1399
+ classname += classNames.delineatorElement;
1400
+ }
1401
+
1402
+ classname += classNames['element' + this.pascalCase(elementName)];
1403
+
1404
+ if (!modifier) return classname;
1405
+
1406
+ if (classname.length) {
1407
+ classname += classNames.delineatorModifier;
1408
+ }
1409
+
1410
+ classname += modifier;
1411
+
1412
+ return classname;
1413
+ },
1414
+
1415
+ /**
1416
+ * Returns the value of a property on a given object via its string key.
1417
+ *
1418
+ * @param {object} obj
1419
+ * @param {string} stringKey
1420
+ * @return {*} value
1421
+ */
1422
+
1423
+ getProperty: function(obj, stringKey) {
1424
+ var parts = stringKey.split('.'),
1425
+ returnCurrent = null,
1426
+ current = '',
1427
+ i = 0;
1428
+
1429
+ if (!stringKey) {
1430
+ return obj;
1431
+ }
1432
+
1433
+ returnCurrent = function(obj) {
1434
+ if (!obj) {
1435
+ return null;
1436
+ } else {
1437
+ return obj[current];
1438
+ }
1439
+ };
1440
+
1441
+ while (i < parts.length) {
1442
+ current = parts[i];
1443
+
1444
+ obj = returnCurrent(obj);
1445
+
1446
+ i++;
1447
+ }
1448
+
1449
+ if (typeof obj !== 'undefined') {
1450
+ return obj;
1451
+ } else {
1452
+ return null;
1453
+ }
1454
+ }
1455
+ };
1456
+
1457
+ mixitup.h = h;
1458
+
1459
+ /**
1460
+ * The Base class adds instance methods to all other extensible MixItUp classes,
1461
+ * enabling the calling of any registered hooks.
1462
+ *
1463
+ * @constructor
1464
+ * @namespace
1465
+ * @memberof mixitup
1466
+ * @private
1467
+ * @since 3.0.0
1468
+ */
1469
+
1470
+ mixitup.Base = function() {};
1471
+
1472
+ mixitup.Base.prototype = {
1473
+ constructor: mixitup.Base,
1474
+
1475
+ /**
1476
+ * Calls any registered hooks for the provided action.
1477
+ *
1478
+ * @memberof mixitup.Base
1479
+ * @private
1480
+ * @instance
1481
+ * @since 2.0.0
1482
+ * @param {string} actionName
1483
+ * @param {Array<*>} args
1484
+ * @return {void}
1485
+ */
1486
+
1487
+ callActions: function(actionName, args) {
1488
+ var self = this,
1489
+ hooks = self.constructor.actions[actionName],
1490
+ extensionName = '';
1491
+
1492
+ if (!hooks || h.isEmptyObject(hooks)) return;
1493
+
1494
+ for (extensionName in hooks) {
1495
+ hooks[extensionName].apply(self, args);
1496
+ }
1497
+ },
1498
+
1499
+ /**
1500
+ * Calls any registered hooks for the provided filter.
1501
+ *
1502
+ * @memberof mixitup.Base
1503
+ * @private
1504
+ * @instance
1505
+ * @since 2.0.0
1506
+ * @param {string} filterName
1507
+ * @param {*} input
1508
+ * @param {Array<*>} args
1509
+ * @return {*}
1510
+ */
1511
+
1512
+ callFilters: function(filterName, input, args) {
1513
+ var self = this,
1514
+ hooks = self.constructor.filters[filterName],
1515
+ output = input,
1516
+ extensionName = '';
1517
+
1518
+ if (!hooks || h.isEmptyObject(hooks)) return output;
1519
+
1520
+ args = args || [];
1521
+
1522
+ for (extensionName in hooks) {
1523
+ args = h.arrayFromList(args);
1524
+
1525
+ args.unshift(output);
1526
+
1527
+ output = hooks[extensionName].apply(self, args);
1528
+ }
1529
+
1530
+ return output;
1531
+ }
1532
+ };
1533
+
1534
+ /**
1535
+ * The BaseStatic class holds a set of static methods which are then added to all other
1536
+ * extensible MixItUp classes as a means of integrating extensions via the addition of new
1537
+ * methods and/or actions and hooks.
1538
+ *
1539
+ * @constructor
1540
+ * @namespace
1541
+ * @memberof mixitup
1542
+ * @private
1543
+ * @since 3.0.0
1544
+ */
1545
+
1546
+ mixitup.BaseStatic = function() {
1547
+ this.actions = {};
1548
+ this.filters = {};
1549
+
1550
+ /**
1551
+ * Performs a shallow extend on the class's prototype, adding one or more new members to
1552
+ * the class in a single operation.
1553
+ *
1554
+ * @memberof mixitup.BaseStatic
1555
+ * @public
1556
+ * @static
1557
+ * @since 2.1.0
1558
+ * @param {object} extension
1559
+ * @return {void}
1560
+ */
1561
+
1562
+ this.extend = function(extension) {
1563
+ h.extend(this.prototype, extension);
1564
+ };
1565
+
1566
+ /**
1567
+ * Registers a function to be called on the action hook of the provided name.
1568
+ *
1569
+ * @memberof mixitup.BaseStatic
1570
+ * @public
1571
+ * @static
1572
+ * @since 2.1.0
1573
+ * @param {string} hookName
1574
+ * @param {string} extensionName
1575
+ * @param {function} func
1576
+ * @return {void}
1577
+ */
1578
+
1579
+ this.registerAction = function(hookName, extensionName, func) {
1580
+ (this.actions[hookName] = this.actions[hookName] || {})[extensionName] = func;
1581
+ };
1582
+
1583
+ /**
1584
+ * Registers a function to be called on the filter of the provided name.
1585
+ *
1586
+ * @memberof mixitup.BaseStatic
1587
+ * @public
1588
+ * @static
1589
+ * @since 2.1.0
1590
+ * @param {string} hookName
1591
+ * @param {string} extensionName
1592
+ * @param {function} func
1593
+ * @return {void}
1594
+ */
1595
+
1596
+ this.registerFilter = function(hookName, extensionName, func) {
1597
+ (this.filters[hookName] = this.filters[hookName] || {})[extensionName] = func;
1598
+ };
1599
+ };
1600
+
1601
+ /**
1602
+ * The `mixitup.Features` class performs all feature and CSS prefix detection
1603
+ * neccessary for MixItUp to function correctly, as well as storing various
1604
+ * string and array constants. All feature decection is on evaluation of the
1605
+ * library and stored in a singleton instance for use by other internal classes.
1606
+ *
1607
+ * @constructor
1608
+ * @namespace
1609
+ * @memberof mixitup
1610
+ * @private
1611
+ * @since 3.0.0
1612
+ */
1613
+
1614
+ mixitup.Features = function() {
1615
+ mixitup.Base.call(this);
1616
+
1617
+ this.callActions('beforeConstruct');
1618
+
1619
+ this.boxSizingPrefix = '';
1620
+ this.transformPrefix = '';
1621
+ this.transitionPrefix = '';
1622
+
1623
+ this.boxSizingPrefix = '';
1624
+ this.transformProp = '';
1625
+ this.transformRule = '';
1626
+ this.transitionProp = '';
1627
+ this.perspectiveProp = '';
1628
+ this.perspectiveOriginProp = '';
1629
+
1630
+ this.has = new mixitup.Has();
1631
+
1632
+ this.canary = null;
1633
+
1634
+ this.BOX_SIZING_PROP = 'boxSizing';
1635
+ this.TRANSITION_PROP = 'transition';
1636
+ this.TRANSFORM_PROP = 'transform';
1637
+ this.PERSPECTIVE_PROP = 'perspective';
1638
+ this.PERSPECTIVE_ORIGIN_PROP = 'perspectiveOrigin';
1639
+ this.VENDORS = ['Webkit', 'moz', 'O', 'ms'];
1640
+
1641
+ this.TWEENABLE = [
1642
+ 'opacity',
1643
+ 'width', 'height',
1644
+ 'marginRight', 'marginBottom',
1645
+ 'x', 'y',
1646
+ 'scale',
1647
+ 'translateX', 'translateY', 'translateZ',
1648
+ 'rotateX', 'rotateY', 'rotateZ'
1649
+ ];
1650
+
1651
+ this.callActions('afterConstruct');
1652
+ };
1653
+
1654
+ mixitup.BaseStatic.call(mixitup.Features);
1655
+
1656
+ mixitup.Features.prototype = Object.create(mixitup.Base.prototype);
1657
+
1658
+ h.extend(mixitup.Features.prototype,
1659
+ /** @lends mixitup.Features */
1660
+ {
1661
+ constructor: mixitup.Features,
1662
+
1663
+ /**
1664
+ * @private
1665
+ * @return {void}
1666
+ */
1667
+
1668
+ init: function() {
1669
+ var self = this;
1670
+
1671
+ self.callActions('beforeInit', arguments);
1672
+
1673
+ self.canary = document.createElement('div');
1674
+
1675
+ self.setPrefixes();
1676
+ self.runTests();
1677
+
1678
+ self.callActions('beforeInit', arguments);
1679
+ },
1680
+
1681
+ /**
1682
+ * @private
1683
+ * @return {void}
1684
+ */
1685
+
1686
+ runTests: function() {
1687
+ var self = this;
1688
+
1689
+ self.callActions('beforeRunTests', arguments);
1690
+
1691
+ self.has.promises = typeof window.Promise === 'function';
1692
+ self.has.transitions = self.transitionPrefix !== 'unsupported';
1693
+
1694
+ self.callActions('afterRunTests', arguments);
1695
+
1696
+ h.freeze(self.has);
1697
+ },
1698
+
1699
+ /**
1700
+ * @private
1701
+ * @return {void}
1702
+ */
1703
+
1704
+ setPrefixes: function() {
1705
+ var self = this;
1706
+
1707
+ self.callActions('beforeSetPrefixes', arguments);
1708
+
1709
+ self.transitionPrefix = h.getPrefix(self.canary, 'Transition', self.VENDORS);
1710
+ self.transformPrefix = h.getPrefix(self.canary, 'Transform', self.VENDORS);
1711
+ self.boxSizingPrefix = h.getPrefix(self.canary, 'BoxSizing', self.VENDORS);
1712
+
1713
+ self.boxSizingProp = self.boxSizingPrefix ?
1714
+ self.boxSizingPrefix + h.pascalCase(self.BOX_SIZING_PROP) : self.BOX_SIZING_PROP;
1715
+
1716
+ self.transitionProp = self.transitionPrefix ?
1717
+ self.transitionPrefix + h.pascalCase(self.TRANSITION_PROP) : self.TRANSITION_PROP;
1718
+
1719
+ self.transformProp = self.transformPrefix ?
1720
+ self.transformPrefix + h.pascalCase(self.TRANSFORM_PROP) : self.TRANSFORM_PROP;
1721
+
1722
+ self.transformRule = self.transformPrefix ?
1723
+ '-' + self.transformPrefix + '-' + self.TRANSFORM_PROP : self.TRANSFORM_PROP;
1724
+
1725
+ self.perspectiveProp = self.transformPrefix ?
1726
+ self.transformPrefix + h.pascalCase(self.PERSPECTIVE_PROP) : self.PERSPECTIVE_PROP;
1727
+
1728
+ self.perspectiveOriginProp = self.transformPrefix ?
1729
+ self.transformPrefix + h.pascalCase(self.PERSPECTIVE_ORIGIN_PROP) :
1730
+ self.PERSPECTIVE_ORIGIN_PROP;
1731
+
1732
+ self.callActions('afterSetPrefixes', arguments);
1733
+ }
1734
+ });
1735
+
1736
+ /**
1737
+ * @constructor
1738
+ * @memberof mixitup
1739
+ * @private
1740
+ * @since 3.0.0
1741
+ */
1742
+
1743
+ mixitup.Has = function() {
1744
+ this.transitions = false;
1745
+ this.promises = false;
1746
+
1747
+ h.seal(this);
1748
+ };
1749
+
1750
+ // Assign a singleton instance to `mixitup.features` and initialise:
1751
+
1752
+ mixitup.features = new mixitup.Features();
1753
+
1754
+ mixitup.features.init();
1755
+
1756
+ /**
1757
+ * A group of properties defining the mixer's animation and effects settings.
1758
+ *
1759
+ * @constructor
1760
+ * @memberof mixitup.Config
1761
+ * @name animation
1762
+ * @namespace
1763
+ * @public
1764
+ * @since 2.0.0
1765
+ */
1766
+
1767
+ mixitup.ConfigAnimation = function() {
1768
+ mixitup.Base.call(this);
1769
+
1770
+ this.callActions('beforeConstruct');
1771
+
1772
+ /**
1773
+ * A boolean dictating whether or not animation should be enabled for the MixItUp instance.
1774
+ * If `false`, all operations will occur instantly and syncronously, although callback
1775
+ * functions and any returned promises will still be fulfilled.
1776
+ *
1777
+ * @example <caption>Example: Create a mixer with all animations disabled</caption>
1778
+ * var mixer = mixitup(containerEl, {
1779
+ * animation: {
1780
+ * enable: false
1781
+ * }
1782
+ * });
1783
+ *
1784
+ * @name enable
1785
+ * @memberof mixitup.Config.animation
1786
+ * @instance
1787
+ * @type {boolean}
1788
+ * @default true
1789
+ */
1790
+
1791
+ this.enable = true;
1792
+
1793
+ /**
1794
+ * A string of one or more space-seperated properties to which transitions will be
1795
+ * applied for all filtering animations.
1796
+ *
1797
+ * Properties can be listed any order or combination, although they will be applied in a specific
1798
+ * predefined order to produce consistent results.
1799
+ *
1800
+ * To learn more about available effects, experiment with our <a href="https://www.kunkalabs.com/mixitup/">
1801
+ * sandbox demo</a> and try out the "Export config" button in the Animation options drop down.
1802
+ *
1803
+ * @example <caption>Example: Apply "fade" and "translateZ" effects to all animations</caption>
1804
+ * // As targets are filtered in and out, they will fade between
1805
+ * // opacity 1 and 0 and transform between translateZ(-100px) and
1806
+ * // translateZ(0).
1807
+ *
1808
+ * var mixer = mixitup(containerEl, {
1809
+ * animation: {
1810
+ * effects: 'fade translateZ(-100px)'
1811
+ * }
1812
+ * });
1813
+ *
1814
+ * @name effects
1815
+ * @memberof mixitup.Config.animation
1816
+ * @instance
1817
+ * @type {string}
1818
+ * @default 'fade scale'
1819
+ */
1820
+
1821
+ this.effects = 'fade scale';
1822
+
1823
+ /**
1824
+ * A string of one or more space-seperated effects to be applied only to filter-in
1825
+ * animations, overriding `config.animation.effects` if set.
1826
+ *
1827
+ * @example <caption>Example: Apply downwards vertical translate to targets being filtered in</caption>
1828
+ *
1829
+ * var mixer = mixitup(containerEl, {
1830
+ * animation: {
1831
+ * effectsIn: 'fade translateY(-100%)'
1832
+ * }
1833
+ * });
1834
+ *
1835
+ * @name effectsIn
1836
+ * @memberof mixitup.Config.animation
1837
+ * @instance
1838
+ * @type {string}
1839
+ * @default ''
1840
+ */
1841
+
1842
+ this.effectsIn = '';
1843
+
1844
+ /**
1845
+ * A string of one or more space-seperated effects to be applied only to filter-out
1846
+ * animations, overriding `config.animation.effects` if set.
1847
+ *
1848
+ * @example <caption>Example: Apply upwards vertical translate to targets being filtered out</caption>
1849
+ *
1850
+ * var mixer = mixitup(containerEl, {
1851
+ * animation: {
1852
+ * effectsOut: 'fade translateY(-100%)'
1853
+ * }
1854
+ * });
1855
+ *
1856
+ * @name effectsOut
1857
+ * @memberof mixitup.Config.animation
1858
+ * @instance
1859
+ * @type {string}
1860
+ * @default ''
1861
+ */
1862
+
1863
+ this.effectsOut = '';
1864
+
1865
+ /**
1866
+ * An integer dictating the duration of all MixItUp animations in milliseconds, not
1867
+ * including any additional delay apllied via the `'stagger'` effect.
1868
+ *
1869
+ * @example <caption>Example: Apply an animation duration of 200ms to all mixitup animations</caption>
1870
+ *
1871
+ * var mixer = mixitup(containerEl, {
1872
+ * animation: {
1873
+ * duration: 200
1874
+ * }
1875
+ * });
1876
+ *
1877
+ * @name duration
1878
+ * @memberof mixitup.Config.animation
1879
+ * @instance
1880
+ * @type {number}
1881
+ * @default 600
1882
+ */
1883
+
1884
+ this.duration = 600;
1885
+
1886
+ /**
1887
+ * A valid CSS3 transition-timing function or shorthand. For a full list of accepted
1888
+ * values, visit <a href="http://easings.net" target="_blank">easings.net</a>.
1889
+ *
1890
+ * @example <caption>Example 1: Apply "ease-in-out" easing to all animations</caption>
1891
+ *
1892
+ * var mixer = mixitup(containerEl, {
1893
+ * animation: {
1894
+ * easing: 'ease-in-out'
1895
+ * }
1896
+ * });
1897
+ *
1898
+ * @example <caption>Example 2: Apply a custom "cubic-bezier" easing function to all animations</caption>
1899
+ * var mixer = mixitup(containerEl, {
1900
+ * animation: {
1901
+ * easing: 'cubic-bezier(0.645, 0.045, 0.355, 1)'
1902
+ * }
1903
+ * });
1904
+ *
1905
+ * @name easing
1906
+ * @memberof mixitup.Config.animation
1907
+ * @instance
1908
+ * @type {string}
1909
+ * @default 'ease'
1910
+ */
1911
+
1912
+ this.easing = 'ease';
1913
+
1914
+ /**
1915
+ * A boolean dictating whether or not to apply perspective to the MixItUp container
1916
+ * during animations. By default, perspective is always applied and creates the
1917
+ * illusion of three-dimensional space for effects such as `translateZ`, `rotateX`,
1918
+ * and `rotateY`.
1919
+ *
1920
+ * You may wish to disable this and define your own perspective settings via CSS.
1921
+ *
1922
+ * @example <caption>Example: Prevent perspective from being applied to any 3D transforms</caption>
1923
+ * var mixer = mixitup(containerEl, {
1924
+ * animation: {
1925
+ * applyPerspective: false
1926
+ * }
1927
+ * });
1928
+ *
1929
+ * @name applyPerspective
1930
+ * @memberof mixitup.Config.animation
1931
+ * @instance
1932
+ * @type {bolean}
1933
+ * @default true
1934
+ */
1935
+
1936
+ this.applyPerspective = true;
1937
+
1938
+ /**
1939
+ * The perspective distance value to be applied to the container during animations,
1940
+ * affecting any 3D-transform-based effects.
1941
+ *
1942
+ * @example <caption>Example: Set a perspective distance of 2000px</caption>
1943
+ * var mixer = mixitup(containerEl, {
1944
+ * animation: {
1945
+ * effects: 'rotateY(-25deg)',
1946
+ * perspectiveDistance: '2000px'
1947
+ * }
1948
+ * });
1949
+ *
1950
+ * @name perspectiveDistance
1951
+ * @memberof mixitup.Config.animation
1952
+ * @instance
1953
+ * @type {string}
1954
+ * @default '3000px'
1955
+ */
1956
+
1957
+ this.perspectiveDistance = '3000px';
1958
+
1959
+ /**
1960
+ * The perspective-origin value to be applied to the container during animations,
1961
+ * affecting any 3D-transform-based effects.
1962
+ *
1963
+ * @example <caption>Example: Set a perspective origin in the top-right of the container</caption>
1964
+ * var mixer = mixitup(containerEl, {
1965
+ * animation: {
1966
+ * effects: 'transateZ(-200px)',
1967
+ * perspectiveOrigin: '100% 0'
1968
+ * }
1969
+ * });
1970
+ *
1971
+ * @name perspectiveOrigin
1972
+ * @memberof mixitup.Config.animation
1973
+ * @instance
1974
+ * @type {string}
1975
+ * @default '50% 50%'
1976
+ */
1977
+
1978
+ this.perspectiveOrigin = '50% 50%';
1979
+
1980
+ /**
1981
+ * A boolean dictating whether or not to enable the queuing of operations.
1982
+ *
1983
+ * If `true` (default), and a control is clicked or an API call is made while another
1984
+ * operation is progress, the operation will go into the queue and will be automatically exectuted
1985
+ * when the previous operaitons is finished.
1986
+ *
1987
+ * If `false`, any requested operations will be ignored, and the `onMixBusy` callback and `mixBusy`
1988
+ * event will be fired. If `debug.showWarnings` is enabled, a console warning will also occur.
1989
+ *
1990
+ * @example <caption>Example: Disable queuing</caption>
1991
+ * var mixer = mixitup(containerEl, {
1992
+ * animation: {
1993
+ * queue: false
1994
+ * }
1995
+ * });
1996
+ *
1997
+ * @name queue
1998
+ * @memberof mixitup.Config.animation
1999
+ * @instance
2000
+ * @type {boolean}
2001
+ * @default true
2002
+ */
2003
+
2004
+ this.queue = true;
2005
+
2006
+ /**
2007
+ * An integer dictacting the maximum number of operations allowed in the queue at
2008
+ * any time, when queuing is enabled.
2009
+ *
2010
+ * @example <caption>Example: Allow a maximum of 5 operations in the queue at any time</caption>
2011
+ * var mixer = mixitup(containerEl, {
2012
+ * animation: {
2013
+ * queueLimit: 5
2014
+ * }
2015
+ * });
2016
+ *
2017
+ * @name queueLimit
2018
+ * @memberof mixitup.Config.animation
2019
+ * @instance
2020
+ * @type {number}
2021
+ * @default 3
2022
+ */
2023
+
2024
+ this.queueLimit = 3;
2025
+
2026
+ /**
2027
+ * A boolean dictating whether or not to transition the height and width of the
2028
+ * container as elements are filtered in and out. If disabled, the container height
2029
+ * will change abruptly.
2030
+ *
2031
+ * It may be desirable to disable this on mobile devices as the CSS `height` and
2032
+ * `width` properties do not receive GPU-acceleration and can therefore cause stuttering.
2033
+ *
2034
+ * @example <caption>Example 1: Disable the transitioning of the container height and/or width</caption>
2035
+ * var mixer = mixitup(containerEl, {
2036
+ * animation: {
2037
+ * animateResizeContainer: false
2038
+ * }
2039
+ * });
2040
+ *
2041
+ * @example <caption>Example 2: Disable the transitioning of the container height and/or width for mobile devices only</caption>
2042
+ * var mixer = mixitup(containerEl, {
2043
+ * animation: {
2044
+ * animateResizeContainer: myFeatureTests.isMobile ? false : true
2045
+ * }
2046
+ * });
2047
+ *
2048
+ * @name animateResizeContainer
2049
+ * @memberof mixitup.Config.animation
2050
+ * @instance
2051
+ * @type {boolean}
2052
+ * @default true
2053
+ */
2054
+
2055
+ this.animateResizeContainer = true;
2056
+
2057
+ /**
2058
+ * A boolean dictating whether or not to transition the height and width of target
2059
+ * elements as they change throughout the course of an animation.
2060
+ *
2061
+ * This is often a must for flex-box grid layouts where the size of target elements may change
2062
+ * depending on final their position in relation to their siblings, or for `.changeLayout()`
2063
+ * operations where the size of targets change between layouts.
2064
+ *
2065
+ * NB: This feature requires additional calculations and manipulation to non-hardware-accelerated
2066
+ * properties which may adversely affect performance on slower devices, and is therefore
2067
+ * disabled by default.
2068
+ *
2069
+ * @example <caption>Example: Enable the transitioning of target widths and heights</caption>
2070
+ * var mixer = mixitup(containerEl, {
2071
+ * animation: {
2072
+ * animateResizeTargets: true
2073
+ * }
2074
+ * });
2075
+ *
2076
+ * @name animateResizeTargets
2077
+ * @memberof mixitup.Config.animation
2078
+ * @instance
2079
+ * @type {boolean}
2080
+ * @default false
2081
+ */
2082
+
2083
+ this.animateResizeTargets = false;
2084
+
2085
+ /**
2086
+ * A custom function used to manipulate the order in which the stagger delay is
2087
+ * incremented when using the ‘stagger’ effect.
2088
+ *
2089
+ * When using the 'stagger' effect, the delay applied to each target element is incremented
2090
+ * based on its index. You may create a custom function to manipulate the order in which the
2091
+ * delay is incremented and create engaging non-linear stagger effects.
2092
+ *
2093
+ * The function receives the index of the target element as a parameter, and must
2094
+ * return an integer which serves as the multiplier for the stagger delay.
2095
+ *
2096
+ * @example <caption>Example 1: Stagger target elements by column in a 3-column grid</caption>
2097
+ * var mixer = mixitup(containerEl, {
2098
+ * animation: {
2099
+ * effects: 'fade stagger(100ms)',
2100
+ * staggerSequence: function(i) {
2101
+ * return i % 3;
2102
+ * }
2103
+ * }
2104
+ * });
2105
+ *
2106
+ * @example <caption>Example 2: Using an algorithm to produce a more complex sequence</caption>
2107
+ * var mixer = mixitup(containerEl, {
2108
+ * animation: {
2109
+ * effects: 'fade stagger(100ms)',
2110
+ * staggerSequence: function(i) {
2111
+ * return (2*i) - (5*((i/3) - ((1/3) * (i%3))));
2112
+ * }
2113
+ * }
2114
+ * });
2115
+ *
2116
+ * @name staggerSequence
2117
+ * @memberof mixitup.Config.animation
2118
+ * @instance
2119
+ * @type {function}
2120
+ * @default null
2121
+ */
2122
+
2123
+ this.staggerSequence = null;
2124
+
2125
+ /**
2126
+ * A boolean dictating whether or not to reverse the direction of `translate`
2127
+ * and `rotate` transforms for elements being filtered out.
2128
+ *
2129
+ * It can be used to create carousel-like animations where elements enter and exit
2130
+ * from opposite directions. If enabled, the effect `translateX(-100%)` for elements
2131
+ * being filtered in would become `translateX(100%)` for targets being filtered out.
2132
+ *
2133
+ * This functionality can also be achieved by providing seperate effects
2134
+ * strings for `config.animation.effectsIn` and `config.animation.effectsOut`.
2135
+ *
2136
+ * @example <caption>Example: Reverse the desired direction on any translate/rotate effect for targets being filtered out</caption>
2137
+ * // Elements being filtered in will be translated from '100%' to '0' while
2138
+ * // elements being filtered out will be translated from 0 to '-100%'
2139
+ *
2140
+ * var mixer = mixitup(containerEl, {
2141
+ * animation: {
2142
+ * effects: 'fade translateX(100%)',
2143
+ * reverseOut: true,
2144
+ * nudge: false // Disable nudging to create a carousel-like effect
2145
+ * }
2146
+ * });
2147
+ *
2148
+ * @name reverseOut
2149
+ * @memberof mixitup.Config.animation
2150
+ * @instance
2151
+ * @type {boolean}
2152
+ * @default false
2153
+ */
2154
+
2155
+ this.reverseOut = false;
2156
+
2157
+ /**
2158
+ * A boolean dictating whether or not to "nudge" the animation path of targets
2159
+ * when they are being filtered in and out simulatenously.
2160
+ *
2161
+ * This has been the default behavior of MixItUp since version 1, but it
2162
+ * may be desirable to disable this effect when filtering directly from
2163
+ * one exclusive set of targets to a different exclusive set of targets,
2164
+ * to create a carousel-like effect, or a generally more subtle animation.
2165
+ *
2166
+ * @example <caption>Example: Disable the "nudging" of targets being filtered in and out simulatenously</caption>
2167
+ *
2168
+ * var mixer = mixitup(containerEl, {
2169
+ * animation: {
2170
+ * nudge: false
2171
+ * }
2172
+ * });
2173
+ *
2174
+ * @name nudge
2175
+ * @memberof mixitup.Config.animation
2176
+ * @instance
2177
+ * @type {boolean}
2178
+ * @default true
2179
+ */
2180
+
2181
+ this.nudge = true;
2182
+
2183
+ /**
2184
+ * A boolean dictating whether or not to clamp the height of the container while MixItUp's
2185
+ * geometry tests are carried out before an operation.
2186
+ *
2187
+ * To prevent scroll-bar flicker, clamping is turned on by default. But in the case where the
2188
+ * height of the container might affect its vertical positioning in the viewport
2189
+ * (e.g. a vertically-centered container), this should be turned off to ensure accurate
2190
+ * test results and a smooth animation.
2191
+ *
2192
+ * @example <caption>Example: Disable container height-clamping</caption>
2193
+ *
2194
+ * var mixer = mixitup(containerEl, {
2195
+ * animation: {
2196
+ * clampHeight: false
2197
+ * }
2198
+ * });
2199
+ *
2200
+ * @name clampHeight
2201
+ * @memberof mixitup.Config.animation
2202
+ * @instance
2203
+ * @type {boolean}
2204
+ * @default true
2205
+ */
2206
+
2207
+ this.clampHeight = true;
2208
+
2209
+ /**
2210
+ * A boolean dictating whether or not to clamp the width of the container while MixItUp's
2211
+ * geometry tests are carried out before an operation.
2212
+ *
2213
+ * To prevent scroll-bar flicker, clamping is turned on by default. But in the case where the
2214
+ * width of the container might affect its horitzontal positioning in the viewport
2215
+ * (e.g. a horizontall-centered container), this should be turned off to ensure accurate
2216
+ * test results and a smooth animation.
2217
+ *
2218
+ * @example <caption>Example: Disable container width-clamping</caption>
2219
+ *
2220
+ * var mixer = mixitup(containerEl, {
2221
+ * animation: {
2222
+ * clampWidth: false
2223
+ * }
2224
+ * });
2225
+ *
2226
+ * @name clampWidth
2227
+ * @memberof mixitup.Config.animation
2228
+ * @instance
2229
+ * @type {boolean}
2230
+ * @default true
2231
+ */
2232
+
2233
+ this.clampWidth = true;
2234
+
2235
+ this.callActions('afterConstruct');
2236
+
2237
+ h.seal(this);
2238
+ };
2239
+
2240
+ mixitup.BaseStatic.call(mixitup.ConfigAnimation);
2241
+
2242
+ mixitup.ConfigAnimation.prototype = Object.create(mixitup.Base.prototype);
2243
+
2244
+ mixitup.ConfigAnimation.prototype.constructor = mixitup.ConfigAnimation;
2245
+
2246
+ /**
2247
+ * A group of properties relating to the behavior of the Mixer.
2248
+ *
2249
+ * @constructor
2250
+ * @memberof mixitup.Config
2251
+ * @name behavior
2252
+ * @namespace
2253
+ * @public
2254
+ * @since 3.1.12
2255
+ */
2256
+
2257
+ mixitup.ConfigBehavior = function() {
2258
+ mixitup.Base.call(this);
2259
+
2260
+ this.callActions('beforeConstruct');
2261
+
2262
+ /**
2263
+ * A boolean dictating whether to allow "live" sorting of the mixer.
2264
+ *
2265
+ * Because of the expensive nature of sorting, MixItUp makes use of several
2266
+ * internal optimizations to skip redundant sorting operations, such as when
2267
+ * the newly requested sort command is the same as the active one. The caveat
2268
+ * to this optimization is that "live" edits to the value of a target's sorting
2269
+ * attribute will be ignored when requesting a re-sort by the same attribute.
2270
+ *
2271
+ * By setting to `behavior.liveSort` to `true`, the mixer will always re-sort
2272
+ * regardless of whether or not the sorting attribute and order have changed.
2273
+ *
2274
+ * @example <caption>Example: Enabling `liveSort` to allow for re-sorting</caption>
2275
+ *
2276
+ * var mixer = mixitup(containerEl, {
2277
+ * behavior: {
2278
+ * liveSort: true
2279
+ * },
2280
+ * load: {
2281
+ * sort: 'edited:desc'
2282
+ * }
2283
+ * });
2284
+ *
2285
+ * var target = containerEl.children[3];
2286
+ *
2287
+ * console.log(target.getAttribute('data-edited')); // '2015-04-24'
2288
+ *
2289
+ * target.setAttribute('data-edited', '2017-08-10'); // Update the target's edited date
2290
+ *
2291
+ * mixer.sort('edited:desc')
2292
+ * .then(function(state) {
2293
+ * // The target is now at the top of the list
2294
+ *
2295
+ * console.log(state.targets[0] === target); // true
2296
+ * });
2297
+ *
2298
+ * @name liveSort
2299
+ * @memberof mixitup.Config.behavior
2300
+ * @instance
2301
+ * @type {boolean}
2302
+ * @default false
2303
+ */
2304
+
2305
+ this.liveSort = false;
2306
+
2307
+ this.callActions('afterConstruct');
2308
+
2309
+ h.seal(this);
2310
+ };
2311
+
2312
+ mixitup.BaseStatic.call(mixitup.ConfigBehavior);
2313
+
2314
+ mixitup.ConfigBehavior.prototype = Object.create(mixitup.Base.prototype);
2315
+
2316
+ mixitup.ConfigBehavior.prototype.constructor = mixitup.ConfigBehavior;
2317
+
2318
+ /**
2319
+ * A group of optional callback functions to be invoked at various
2320
+ * points within the lifecycle of a mixer operation.
2321
+ *
2322
+ * Each function is analogous to an event of the same name triggered from the
2323
+ * container element, and is invoked immediately after it.
2324
+ *
2325
+ * All callback functions receive the current `state` object as their first
2326
+ * argument, as well as other more specific arguments described below.
2327
+ *
2328
+ * @constructor
2329
+ * @memberof mixitup.Config
2330
+ * @name callbacks
2331
+ * @namespace
2332
+ * @public
2333
+ * @since 2.0.0
2334
+ */
2335
+
2336
+ mixitup.ConfigCallbacks = function() {
2337
+ mixitup.Base.call(this);
2338
+
2339
+ this.callActions('beforeConstruct');
2340
+
2341
+ /**
2342
+ * A callback function invoked immediately after any MixItUp operation is requested
2343
+ * and before animations have begun.
2344
+ *
2345
+ * A second `futureState` argument is passed to the function which represents the final
2346
+ * state of the mixer once the requested operation has completed.
2347
+ *
2348
+ * @example <caption>Example: Adding an `onMixStart` callback function</caption>
2349
+ * var mixer = mixitup(containerEl, {
2350
+ * callbacks: {
2351
+ * onMixStart: function(state, futureState) {
2352
+ * console.log('Starting operation...');
2353
+ * }
2354
+ * }
2355
+ * });
2356
+ *
2357
+ * @name onMixStart
2358
+ * @memberof mixitup.Config.callbacks
2359
+ * @instance
2360
+ * @type {function}
2361
+ * @default null
2362
+ */
2363
+
2364
+ this.onMixStart = null;
2365
+
2366
+ /**
2367
+ * A callback function invoked when a MixItUp operation is requested while another
2368
+ * operation is in progress, and the animation queue is full, or queueing
2369
+ * is disabled.
2370
+ *
2371
+ * @example <caption>Example: Adding an `onMixBusy` callback function</caption>
2372
+ * var mixer = mixitup(containerEl, {
2373
+ * callbacks: {
2374
+ * onMixBusy: function(state) {
2375
+ * console.log('Mixer busy');
2376
+ * }
2377
+ * }
2378
+ * });
2379
+ *
2380
+ * @name onMixBusy
2381
+ * @memberof mixitup.Config.callbacks
2382
+ * @instance
2383
+ * @type {function}
2384
+ * @default null
2385
+ */
2386
+