1256 lines
48 KiB
JavaScript
1256 lines
48 KiB
JavaScript
/**!
|
|
* MixItUp MultiFilter v3.3.6
|
|
* A UI-builder for powerful multidimensional filtering
|
|
* Build 293e0dda-087e-4a76-aadf-e3e8b311b81f
|
|
*
|
|
* Requires mixitup.js >= v^3.1.2
|
|
*
|
|
* @copyright Copyright 2014-2020 KunkaLabs Limited.
|
|
* @author KunkaLabs Limited.
|
|
* @link https://www.kunkalabs.com/mixitup-multifilter/
|
|
*
|
|
* @license Commercial use requires a commercial license.
|
|
* https://www.kunkalabs.com/mixitup-multifilter/licenses/
|
|
*
|
|
* Non-commercial use permitted under same terms as license.
|
|
* http://creativecommons.org/licenses/by-nc/3.0/
|
|
*/
|
|
(function(window) {
|
|
'use strict';
|
|
|
|
var mixitupMultifilter = function(mixitup) {
|
|
var h = mixitup.h;
|
|
var diacriticsMap;
|
|
|
|
diacriticsMap = [
|
|
['A', /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g],
|
|
['AA', /[\uA732]/g],
|
|
['AE', /[\u00C6\u01FC\u01E2]/g],
|
|
['AO', /[\uA734]/g],
|
|
['AU', /[\uA736]/g],
|
|
['AV', /[\uA738\uA73A]/g],
|
|
['AY', /[\uA73C]/g],
|
|
['B', /[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g],
|
|
['C', /[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g],
|
|
['D', /[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g],
|
|
['DZ', /[\u01F1\u01C4]/g],
|
|
['Dz', /[\u01F2\u01C5]/g],
|
|
['E', /[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g],
|
|
['F', /[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g],
|
|
['G', /[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g],
|
|
['H', /[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g],
|
|
['I', /[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g],
|
|
['J', /[\u004A\u24BF\uFF2A\u0134\u0248]/g],
|
|
['K', /[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g],
|
|
['L', /[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g],
|
|
['LJ', /[\u01C7]/g],
|
|
['Lj', /[\u01C8]/g],
|
|
['M', /[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g],
|
|
['N', /[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g],
|
|
['NJ', /[\u01CA]/g],
|
|
['Nj', /[\u01CB]/g],
|
|
['O', /[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g],
|
|
['OI', /[\u01A2]/g],
|
|
['OO', /[\uA74E]/g],
|
|
['OU', /[\u0222]/g],
|
|
['P', /[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g],
|
|
['Q', /[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g],
|
|
['R', /[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g],
|
|
['S', /[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g],
|
|
['T', /[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g],
|
|
['TZ', /[\uA728]/g],
|
|
['U', /[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g],
|
|
['V', /[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g],
|
|
['VY', /[\uA760]/g],
|
|
['W', /[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g],
|
|
['X', /[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g],
|
|
['Y', /[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g],
|
|
['Z', /[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g],
|
|
['a', /[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g],
|
|
['aa', /[\uA733]/g],
|
|
['ae', /[\u00E6\u01FD\u01E3]/g],
|
|
['ao', /[\uA735]/g],
|
|
['au', /[\uA737]/g],
|
|
['av', /[\uA739\uA73B]/g],
|
|
['ay', /[\uA73D]/g],
|
|
['b', /[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g],
|
|
['c', /[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g],
|
|
['d', /[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g],
|
|
['dz', /[\u01F3\u01C6]/g],
|
|
['e', /[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g],
|
|
['f', /[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g],
|
|
['g', /[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g],
|
|
['h', /[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g],
|
|
['hv', /[\u0195]/g],
|
|
['i', /[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g],
|
|
['j', /[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g],
|
|
['k', /[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g],
|
|
['l', /[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g],
|
|
['lj', /[\u01C9]/g],
|
|
['m', /[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g],
|
|
['n', /[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g],
|
|
['nj', /[\u01CC]/g],
|
|
['o', /[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g],
|
|
['oi', /[\u01A3]/g],
|
|
['ou', /[\u0223]/g],
|
|
['oo', /[\uA74F]/g],
|
|
['p', /[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g],
|
|
['q', /[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g],
|
|
['r', /[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g],
|
|
['s', /[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g],
|
|
['t', /[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g],
|
|
['tz', /[\uA729]/g],
|
|
['u', /[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g],
|
|
['v', /[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g],
|
|
['vy', /[\uA761]/g],
|
|
['w', /[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g],
|
|
['x', /[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g],
|
|
['y', /[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g],
|
|
['z', /[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g]
|
|
];
|
|
|
|
if (
|
|
!mixitup.CORE_VERSION ||
|
|
!h.compareVersions(mixitupMultifilter.REQUIRE_CORE_VERSION, mixitup.CORE_VERSION)
|
|
) {
|
|
throw new Error(
|
|
'[MixItUp Multifilter] MixItUp Multifilter v' +
|
|
mixitupMultifilter.EXTENSION_VERSION +
|
|
' requires at least MixItUp v' +
|
|
mixitupMultifilter.REQUIRE_CORE_VERSION
|
|
);
|
|
}
|
|
|
|
/**
|
|
* A group of optional callback functions to be invoked at various
|
|
* points within the lifecycle of a mixer operation.
|
|
*
|
|
* @constructor
|
|
* @memberof mixitup.Config
|
|
* @name callbacks
|
|
* @namespace
|
|
* @public
|
|
* @since 3.0.0
|
|
*/
|
|
|
|
mixitup.ConfigCallbacks.registerAction('afterConstruct', 'multifilter', function() {
|
|
/**
|
|
* A callback function invoked whenever MultiFilter filter groups
|
|
* are parsed. This occurs whenever the user interacts with filter
|
|
* group UI, or when the `parseFilterGroups()` API method is called,
|
|
* but before the resulting filter operation has been triggered.
|
|
*
|
|
* By default, this generates the appropriate compound selector and
|
|
* filters the mixer using a `multimix()` API call internally. This
|
|
* callback can be used to transform the multimix command object sent
|
|
* to this API call.
|
|
*
|
|
* This is particularly useful when additional behavior such as sorting
|
|
* or pagination must be taken into account when using the MultiFilter API.
|
|
*
|
|
* The callback receives the generated multimix command object, and must
|
|
* also return a valid multimix command object.
|
|
*
|
|
* @example <caption>Example: Overriding the default filtering behavior with `onParseFilterGroups`</caption>
|
|
* var mixer = mixitup(containerEl, {
|
|
* callbacks: {
|
|
* onParseFilterGroups: function(command) {
|
|
* command.paginate = 3;
|
|
* command.sort = 'default:desc';
|
|
*
|
|
* return command;
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* @name onParseFilterGroups
|
|
* @memberof mixitup.Config.callbacks
|
|
* @instance
|
|
* @type {function}
|
|
* @default null
|
|
*/
|
|
|
|
this.onParseFilterGroups = null;
|
|
});
|
|
|
|
/**
|
|
* A group of properties defining the behavior of your multifilter UI.
|
|
*
|
|
* @constructor
|
|
* @memberof mixitup.Config
|
|
* @name multifilter
|
|
* @namespace
|
|
* @public
|
|
* @since 3.0.0
|
|
*/
|
|
|
|
mixitup.ConfigMultifilter = function() {
|
|
|
|
/**
|
|
* A boolean dictating whether or not to enable multifilter functionality.
|
|
*
|
|
* If `true`, MixItUp will query the DOM for any elements with a
|
|
* `data-filter-group` attribute present on instantiation.
|
|
*
|
|
* @name enable
|
|
* @memberof mixitup.Config.multifilter
|
|
* @instance
|
|
* @type {boolean}
|
|
* @default false
|
|
*/
|
|
|
|
this.enable = false;
|
|
|
|
/**
|
|
* A string dictating the logic to use when concatenating selectors within
|
|
* individual filter groups.
|
|
*
|
|
* If set to `'or'` (default), targets will be shown if they match any
|
|
* active filter in the group.
|
|
*
|
|
* If set to `'and'`, targets will be shown only if they match
|
|
* all active filters in the group.
|
|
*
|
|
* @name logicWithinGroup
|
|
* @memberof mixitup.Config.multifilter
|
|
* @instance
|
|
* @type {string}
|
|
* @default 'or'
|
|
*/
|
|
|
|
this.logicWithinGroup = 'or';
|
|
|
|
/**
|
|
* A string dictating the logic to use when concatenating each group's
|
|
* selectors into one single selector.
|
|
*
|
|
* If set to `'and'` (default), targets will be shown only if they match
|
|
* the combined active selectors of all groups.
|
|
*
|
|
* If set to `'or'`, targets will be shown if they match the active selectors
|
|
* of any individual group.
|
|
*
|
|
* @name logicBetweenGroups
|
|
* @memberof mixitup.Config.multifilter
|
|
* @instance
|
|
* @type {string}
|
|
* @default 'and'
|
|
*/
|
|
|
|
this.logicBetweenGroups = 'and';
|
|
|
|
/**
|
|
* An integer dictating the minimum number of characters at which the value
|
|
* of a text input will be included as a multifilter. This prevents short or
|
|
* incomplete words with many potential matches from triggering
|
|
* filter operations.
|
|
*
|
|
* @name minSearchLength
|
|
* @memberof mixitup.Config.multifilter
|
|
* @instance
|
|
* @type {number}
|
|
* @default 3
|
|
*/
|
|
|
|
this.minSearchLength = 3;
|
|
|
|
/**
|
|
* A string dictating when the parsing of filter groups should occur.
|
|
*
|
|
* If set to `'change'` (default), the mixer will be filtered whenever the
|
|
* filtering UI is interacted with. The mode provides real-time filtering with
|
|
* instant feedback.
|
|
*
|
|
* If set to `'submit'`, the mixer will only be filtered when a submit button is
|
|
* clicked (if using a `<form>` element as a parent). This enables the user to firstly
|
|
* make their selection, and then trigger filtering once they have
|
|
* finished making their selection.
|
|
*
|
|
* Alternatively, the `mixer.parseFilterGroups()` method can be called via the API at any
|
|
* time to trigger the parsing of filter groups and filter the mixer.
|
|
*
|
|
* @name parseOn
|
|
* @memberof mixitup.Config.multifilter
|
|
* @instance
|
|
* @type {string}
|
|
* @default 'change'
|
|
*/
|
|
|
|
this.parseOn = 'change';
|
|
|
|
/**
|
|
* An integer dictating the duration in ms that must elapse between keyup
|
|
* events in order to trigger a change.
|
|
*
|
|
* Setting a comfortable delay of ~350ms prevents the mixer from being
|
|
* thrashed while typing occurs.
|
|
*
|
|
* @name keyupThrottleDuration
|
|
* @memberof mixitup.Config.multifilter
|
|
* @instance
|
|
* @type {number}
|
|
* @default 350
|
|
*/
|
|
|
|
this.keyupThrottleDuration = 350;
|
|
|
|
h.seal(this);
|
|
};
|
|
|
|
/**
|
|
* The MixItUp configuration object is extended with properties relating to
|
|
* the MultiFilter extension.
|
|
*
|
|
* For the full list of configuration options, please refer to the MixItUp
|
|
* core documentation.
|
|
*
|
|
* @constructor
|
|
* @memberof mixitup
|
|
* @name Config
|
|
* @namespace
|
|
* @public
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
mixitup.Config.registerAction('beforeConstruct', 'multifilter', function() {
|
|
this.multifilter = new mixitup.ConfigMultifilter();
|
|
});
|
|
|
|
mixitup.MultifilterFormEventTracker = function() {
|
|
this.form = null;
|
|
this.totalBound = 0;
|
|
this.totalHandled = 0;
|
|
|
|
h.seal(this);
|
|
};
|
|
|
|
mixitup.FilterGroupDom = function() {
|
|
this.el = null;
|
|
this.form = null;
|
|
|
|
h.seal(this);
|
|
};
|
|
|
|
mixitup.FilterGroup = function() {
|
|
this.name = '';
|
|
this.dom = new mixitup.FilterGroupDom();
|
|
this.activeSelectors = [];
|
|
this.activeFilters = [];
|
|
this.activeToggles = [];
|
|
this.handler = null;
|
|
this.mixer = null;
|
|
this.logic = 'or';
|
|
this.parseOn = 'change';
|
|
this.keyupTimeout = -1;
|
|
|
|
h.seal(this);
|
|
};
|
|
|
|
h.extend(mixitup.FilterGroup.prototype, {
|
|
|
|
/**
|
|
* @private
|
|
* @param {HTMLELement} el
|
|
* @param {mixitup.Mixer} mixer
|
|
* @return {void}
|
|
*/
|
|
|
|
init: function(el, mixer) {
|
|
var self = this,
|
|
logic = el.getAttribute('data-logic');
|
|
|
|
self.dom.el = el;
|
|
|
|
this.name = self.dom.el.getAttribute('data-filter-group') || '';
|
|
|
|
self.cacheDom();
|
|
|
|
if (self.dom.form) {
|
|
self.enableButtons();
|
|
}
|
|
|
|
self.mixer = mixer;
|
|
|
|
if ((logic && logic.toLowerCase() === 'and') || mixer.config.multifilter.logicWithinGroup === 'and') {
|
|
// override default group logic
|
|
|
|
self.logic = 'and';
|
|
|
|
}
|
|
|
|
self.bindEvents();
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @return {void}
|
|
*/
|
|
|
|
cacheDom: function() {
|
|
var self = this;
|
|
|
|
self.dom.form = h.closestParent(self.dom.el, 'form', true);
|
|
},
|
|
|
|
enableButtons: function() {
|
|
var self = this,
|
|
buttons = self.dom.form.querySelectorAll('button[type="submit"]:disabled'),
|
|
button = null,
|
|
i = -1;
|
|
|
|
for (i = 0; button = buttons[i]; i++) {
|
|
if (button.disabled) {
|
|
button.disabled = false;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @return {void}
|
|
*/
|
|
|
|
bindEvents: function() {
|
|
var self = this;
|
|
|
|
self.handler = function(e) {
|
|
switch (e.type) {
|
|
case 'reset':
|
|
case 'submit':
|
|
self.handleFormEvent(e);
|
|
|
|
break;
|
|
default:
|
|
self['handle' + h.pascalCase(e.type)](e);
|
|
}
|
|
};
|
|
|
|
h.on(self.dom.el, 'click', self.handler);
|
|
h.on(self.dom.el, 'change', self.handler);
|
|
h.on(self.dom.el, 'keyup', self.handler);
|
|
|
|
if (self.dom.form) {
|
|
h.on(self.dom.form, 'reset', self.handler);
|
|
h.on(self.dom.form, 'submit', self.handler);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @return {void}
|
|
*/
|
|
|
|
unbindEvents: function() {
|
|
var self = this;
|
|
|
|
h.off(self.dom.el, 'click', self.handler);
|
|
h.off(self.dom.el, 'change', self.handler);
|
|
h.off(self.dom.el, 'keyup', self.handler);
|
|
|
|
if (self.dom.form) {
|
|
h.off(self.dom.form, 'reset', self.handler);
|
|
h.off(self.dom.form, 'submit', self.handler);
|
|
}
|
|
|
|
self.handler = null;
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {MouseEvent} e
|
|
* @return {void}
|
|
*/
|
|
|
|
handleClick: function(e) {
|
|
var self = this,
|
|
mixer = self.mixer,
|
|
returnValue = null,
|
|
controlEl = h.closestParent(e.target, '[data-filter], [data-toggle]', true),
|
|
controlSelector = '',
|
|
index = -1,
|
|
selector = '';
|
|
|
|
if (!controlEl) return;
|
|
|
|
if ((controlSelector = self.mixer.config.selectors.control) && !controlEl.matches(controlSelector)) {
|
|
return;
|
|
}
|
|
|
|
e.stopPropagation();
|
|
|
|
if (!mixer.lastClicked) {
|
|
mixer.lastClicked = controlEl;
|
|
}
|
|
|
|
if (typeof mixer.config.callbacks.onMixClick === 'function') {
|
|
returnValue = mixer.config.callbacks.onMixClick.call(mixer.lastClicked, mixer.state, e, self);
|
|
|
|
if (returnValue === false) {
|
|
// User has returned `false` from the callback, so do not handle click
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (controlEl.matches('[data-filter]')) {
|
|
selector = controlEl.getAttribute('data-filter');
|
|
|
|
self.activeToggles = [];
|
|
self.activeSelectors = self.activeFilters = [selector];
|
|
} else if (controlEl.matches('[data-toggle]')) {
|
|
selector = controlEl.getAttribute('data-toggle');
|
|
|
|
self.activeFilters = [];
|
|
|
|
if ((index = self.activeToggles.indexOf(selector)) > -1) {
|
|
self.activeToggles.splice(index, 1);
|
|
} else {
|
|
self.activeToggles.push(selector);
|
|
}
|
|
|
|
if (self.logic === 'and') {
|
|
// Compress into single node
|
|
|
|
self.activeSelectors = [self.activeToggles];
|
|
} else {
|
|
self.activeSelectors = self.activeToggles;
|
|
}
|
|
}
|
|
|
|
self.updateControls();
|
|
|
|
if (self.mixer.config.multifilter.parseOn === 'change') {
|
|
self.mixer.parseFilterGroups();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {Event} e
|
|
* @return {void}
|
|
*/
|
|
|
|
handleChange: function(e) {
|
|
var self = this,
|
|
input = e.target;
|
|
|
|
e.stopPropagation();
|
|
|
|
switch(input.type) {
|
|
case 'text':
|
|
case 'search':
|
|
case 'email':
|
|
case 'select-one':
|
|
case 'radio':
|
|
self.getSingleValue(input);
|
|
|
|
break;
|
|
case 'checkbox':
|
|
case 'select-multiple':
|
|
self.getMultipleValues(input);
|
|
|
|
break;
|
|
}
|
|
|
|
if (self.mixer.config.multifilter.parseOn === 'change') {
|
|
self.mixer.parseFilterGroups();
|
|
}
|
|
},
|
|
|
|
handleKeyup: function(e) {
|
|
var self = this,
|
|
input = e.target;
|
|
|
|
// NB: Selects can fire keyup events (e.g. multiselect, textual search)
|
|
|
|
if (['text', 'search', 'email'].indexOf(input.type) < 0) return;
|
|
|
|
if (self.mixer.config.multifilter.parseOn !== 'change') {
|
|
self.mixer.getSingleValue(input);
|
|
|
|
return;
|
|
}
|
|
|
|
clearTimeout(self.keyupTimeout);
|
|
|
|
self.keyupTimeout = setTimeout(function() {
|
|
self.getSingleValue(input);
|
|
self.mixer.parseFilterGroups();
|
|
}, self.mixer.config.multifilter.keyupThrottleDuration);
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {Event} e
|
|
* @return {void}
|
|
*/
|
|
|
|
handleFormEvent: function(e) {
|
|
var self = this,
|
|
tracker = null,
|
|
group = null,
|
|
i = -1;
|
|
|
|
if (e.type === 'submit') {
|
|
e.preventDefault();
|
|
}
|
|
|
|
if (e.type === 'reset') {
|
|
self.activeFilters =
|
|
self.activeToggles =
|
|
self.activeSelectors = [];
|
|
|
|
self.updateControls();
|
|
}
|
|
|
|
if (!self.mixer.multifilterFormEventTracker) {
|
|
tracker = self.mixer.multifilterFormEventTracker = new mixitup.MultifilterFormEventTracker();
|
|
|
|
tracker.form = e.target;
|
|
|
|
for (i = 0; group = self.mixer.filterGroups[i]; i++) {
|
|
if (group.dom.form !== e.target) continue;
|
|
|
|
tracker.totalBound++;
|
|
}
|
|
} else {
|
|
tracker = self.mixer.multifilterFormEventTracker;
|
|
}
|
|
|
|
if (e.target === tracker.form) {
|
|
tracker.totalHandled++;
|
|
|
|
if (tracker.totalHandled === tracker.totalBound) {
|
|
self.mixer.multifilterFormEventTracker = null;
|
|
|
|
if (e.type === 'submit' || self.mixer.config.multifilter.parseOn === 'change') {
|
|
self.mixer.parseFilterGroups();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {HTMLELement} input
|
|
* @return {void}
|
|
*/
|
|
|
|
getSingleValue: function(input) {
|
|
var self = this,
|
|
diacriticMap = null,
|
|
attributeName = '',
|
|
selector = '',
|
|
value = '',
|
|
i = -1;
|
|
|
|
if (input.type.match(/text|search|email/g)) {
|
|
attributeName = input.getAttribute('data-search-attribute');
|
|
|
|
if (!attributeName) {
|
|
throw new Error('[MixItUp MultiFilter] A valid `data-search-attribute` must be present on text inputs');
|
|
}
|
|
|
|
if (input.value.length < self.mixer.config.multifilter.minSearchLength) {
|
|
self.activeSelectors = self.activeFilters = self.activeToggles = [''];
|
|
|
|
return;
|
|
}
|
|
|
|
// Lowercase and trim
|
|
|
|
value = input.value.toLowerCase().trim();
|
|
|
|
// Replace diacritics
|
|
|
|
for (i = 0; (diacriticMap = diacriticsMap[i]); i++) {
|
|
value = value.replace(diacriticMap[1], diacriticMap[0]);
|
|
}
|
|
|
|
// Strip non-word characters
|
|
|
|
value = value.replace(/\W+/g, ' ');
|
|
|
|
selector = '[' + attributeName + '*="' + value + '"]';
|
|
} else {
|
|
selector = input.value;
|
|
}
|
|
|
|
if (typeof input.value === 'string') {
|
|
self.activeSelectors =
|
|
self.activeToggles =
|
|
self.activeFilters =
|
|
selector ? [selector] : [];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {HTMLELement} input
|
|
* @return {void}
|
|
*/
|
|
|
|
getMultipleValues: function(input) {
|
|
var self = this,
|
|
activeToggles = [],
|
|
query = '',
|
|
item = null,
|
|
items = null,
|
|
i = -1;
|
|
|
|
switch (input.type) {
|
|
case 'checkbox':
|
|
query = 'input[type="checkbox"]';
|
|
|
|
break;
|
|
case 'select-multiple':
|
|
query = 'option';
|
|
}
|
|
|
|
items = self.dom.el.querySelectorAll(query);
|
|
|
|
for (i = 0; item = items[i]; i++) {
|
|
if ((item.checked || item.selected) && item.value) {
|
|
activeToggles.push(item.value);
|
|
}
|
|
}
|
|
|
|
self.activeFilters = [];
|
|
self.activeToggles = activeToggles;
|
|
|
|
if (self.logic === 'and') {
|
|
// Compress into single node
|
|
|
|
self.activeSelectors = [activeToggles];
|
|
} else {
|
|
self.activeSelectors = activeToggles;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {Array.<HTMLELement>} [controlEls]
|
|
* @return {void}
|
|
*/
|
|
|
|
updateControls: function(controlEls) {
|
|
var self = this,
|
|
controlEl = null,
|
|
controlSelector = '',
|
|
controlsSelector = '',
|
|
type = '',
|
|
i = -1;
|
|
|
|
controlSelector = self.mixer.config.selectors.control.trim();
|
|
|
|
controlsSelector = [
|
|
'[data-filter]' + controlSelector,
|
|
'[data-toggle]' + controlSelector
|
|
].join(', ');
|
|
|
|
controlEls = controlEls || self.dom.el.querySelectorAll(controlsSelector);
|
|
|
|
for (i = 0; controlEl = controlEls[i]; i++) {
|
|
type = Boolean(controlEl.getAttribute('data-toggle')) ? 'toggle' : 'filter';
|
|
|
|
self.updateControl(controlEl, type);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {HTMLELement} controlEl
|
|
* @param {string} type
|
|
* @return {void}
|
|
*/
|
|
|
|
updateControl: function(controlEl, type) {
|
|
var self = this,
|
|
selector = controlEl.getAttribute('data-' + type),
|
|
activeControls = self.activeToggles.concat(self.activeFilters),
|
|
activeClassName = '';
|
|
|
|
activeClassName = h.getClassname(self.mixer.config.classNames, type, self.mixer.config.classNames.modifierActive);
|
|
|
|
if (activeControls.indexOf(selector) > -1) {
|
|
h.addClass(controlEl, activeClassName);
|
|
} else {
|
|
h.removeClass(controlEl, activeClassName);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
|
|
updateUi: function() {
|
|
var self = this,
|
|
controlEls = self.dom.el.querySelectorAll('[data-filter], [data-toggle]'),
|
|
inputEls = self.dom.el.querySelectorAll('input[type="radio"], input[type="checkbox"], option'),
|
|
activeControls = self.activeToggles.concat(self.activeFilters),
|
|
isActive = false,
|
|
inputEl = null,
|
|
i = -1;
|
|
|
|
if (controlEls.length) {
|
|
self.updateControls(controlEls, true);
|
|
}
|
|
|
|
for (i = 0; inputEl = inputEls[i]; i++) {
|
|
isActive = activeControls.indexOf(inputEl.value) > -1;
|
|
|
|
switch (inputEl.tagName.toLowerCase()) {
|
|
case 'option':
|
|
inputEl.selected = isActive;
|
|
|
|
break;
|
|
case 'input':
|
|
inputEl.checked = isActive;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
mixitup.MixerDom.registerAction('afterConstruct', 'multifilter', function() {
|
|
this.filterGroups = [];
|
|
});
|
|
|
|
/**
|
|
* The `mixitup.Mixer` class is extended with API methods relating to
|
|
* the MultiFilter extension.
|
|
*
|
|
* For the full list of API methods, please refer to the MixItUp
|
|
* core documentation.
|
|
*
|
|
* @constructor
|
|
* @namespace
|
|
* @name Mixer
|
|
* @memberof mixitup
|
|
* @public
|
|
* @since 3.0.0
|
|
*/
|
|
|
|
mixitup.Mixer.registerAction('afterConstruct', 'multifilter', function() {
|
|
this.filterGroups = [];
|
|
this.filterGroupsHash = {};
|
|
this.multifilterFormEventTracker = null;
|
|
});
|
|
|
|
mixitup.Mixer.registerAction('afterCacheDom', 'multifilter', function() {
|
|
var self = this,
|
|
parent = null;
|
|
|
|
if (!self.config.multifilter.enable) return;
|
|
|
|
switch (self.config.controls.scope) {
|
|
case 'local':
|
|
parent = self.dom.container;
|
|
|
|
break;
|
|
case 'global':
|
|
parent = self.dom.document;
|
|
|
|
break;
|
|
default:
|
|
throw new Error(mixitup.messages.ERROR_CONFIG_INVALID_CONTROLS_SCOPE);
|
|
}
|
|
|
|
self.dom.filterGroups = parent.querySelectorAll('[data-filter-group]');
|
|
});
|
|
|
|
mixitup.Mixer.registerAction('beforeInitControls', 'multifilter', function() {
|
|
var self = this;
|
|
|
|
if (!self.config.multifilter.enable) return;
|
|
|
|
self.config.controls.live = true; // force live controls if multifilter is enabled
|
|
});
|
|
|
|
mixitup.Mixer.registerAction('afterSanitizeConfig', 'multifilter', function() {
|
|
var self = this;
|
|
|
|
self.config.multifilter.logicBetweenGroups = self.config.multifilter.logicBetweenGroups.toLowerCase().trim();
|
|
self.config.multifilter.logicWithinGroup = self.config.multifilter.logicWithinGroup.toLowerCase().trim();
|
|
});
|
|
|
|
mixitup.Mixer.registerAction('afterAttach', 'multifilter', function() {
|
|
var self = this;
|
|
|
|
if (self.dom.filterGroups.length) {
|
|
self.indexFilterGroups();
|
|
}
|
|
});
|
|
|
|
mixitup.Mixer.registerAction('afterUpdateControls', 'multifilter', function() {
|
|
var self = this,
|
|
group = null,
|
|
i = -1;
|
|
|
|
for (i = 0; group = self.filterGroups[i]; i++) {
|
|
group.updateControls();
|
|
}
|
|
});
|
|
|
|
mixitup.Mixer.registerAction('beforeDestroy', 'multifilter', function() {
|
|
var self = this,
|
|
group = null,
|
|
i = -1;
|
|
|
|
for (i = 0; group = self.filterGroups[i]; i++) {
|
|
group.unbindEvents();
|
|
}
|
|
});
|
|
|
|
mixitup.Mixer.extend(
|
|
/** @lends mixitup.Mixer */
|
|
{
|
|
/**
|
|
* @private
|
|
* @return {void}
|
|
*/
|
|
|
|
indexFilterGroups: function() {
|
|
var self = this,
|
|
filterGroup = null,
|
|
el = null,
|
|
i = -1;
|
|
|
|
for (i = 0; el = self.dom.filterGroups[i]; i++) {
|
|
filterGroup = new mixitup.FilterGroup();
|
|
|
|
filterGroup.init(el, self);
|
|
|
|
self.filterGroups.push(filterGroup);
|
|
|
|
if (filterGroup.name) {
|
|
// If present, also index by name
|
|
|
|
if (typeof self.filterGroupsHash[filterGroup.name] !== 'undefined') {
|
|
throw new Error('[MixItUp MultiFilter] A filter group with name "' + filterGroup.name + '" already exists');
|
|
}
|
|
|
|
self.filterGroupsHash[filterGroup.name] = filterGroup;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @instance
|
|
* @since 2.0.0
|
|
* @param {Array<*>} args
|
|
* @return {mixitup.UserInstruction}
|
|
*/
|
|
|
|
parseParseFilterGroupsArgs: function(args) {
|
|
var self = this,
|
|
instruction = new mixitup.UserInstruction(),
|
|
arg = null,
|
|
i = -1;
|
|
|
|
instruction.animate = self.config.animation.enable;
|
|
instruction.command = new mixitup.CommandFilter();
|
|
|
|
for (i = 0; i < args.length; i++) {
|
|
arg = args[i];
|
|
|
|
if (typeof arg === 'boolean') {
|
|
instruction.animate = arg;
|
|
} else if (typeof arg === 'function') {
|
|
instruction.callback = arg;
|
|
}
|
|
}
|
|
|
|
h.freeze(instruction);
|
|
|
|
return instruction;
|
|
},
|
|
|
|
/**
|
|
* Recursively builds up paths between all possible permutations
|
|
* of filter group nodes according to the defined logic.
|
|
*
|
|
* @private
|
|
* @return {Array.<Array.<string>>}
|
|
*/
|
|
|
|
getFilterGroupPaths: function() {
|
|
var self = this,
|
|
buildPath = null,
|
|
crawl = null,
|
|
nodes = null,
|
|
matrix = [],
|
|
paths = [],
|
|
trackers = [],
|
|
i = -1;
|
|
|
|
for (i = 0; i < self.filterGroups.length; i++) {
|
|
// Filter out groups without any active filters
|
|
|
|
if ((nodes = self.filterGroups[i].activeSelectors).length) {
|
|
matrix.push(nodes);
|
|
|
|
// Initialise tracker for each group
|
|
|
|
trackers.push(0);
|
|
}
|
|
}
|
|
|
|
buildPath = function() {
|
|
var node = null,
|
|
path = [],
|
|
i = -1;
|
|
|
|
for (i = 0; i < matrix.length; i++) {
|
|
node = matrix[i][trackers[i]];
|
|
|
|
if (Array.isArray(node)) {
|
|
// AND logic within group
|
|
|
|
node = node.join('');
|
|
}
|
|
|
|
path.push(node);
|
|
}
|
|
|
|
path = h.clean(path);
|
|
|
|
paths.push(path);
|
|
};
|
|
|
|
crawl = function(index) {
|
|
index = index || 0;
|
|
|
|
var nodes = matrix[index];
|
|
|
|
while (trackers[index] < nodes.length) {
|
|
if (index < matrix.length - 1) {
|
|
// If not last, recurse
|
|
|
|
crawl(index + 1);
|
|
} else {
|
|
// Last, build selector
|
|
|
|
buildPath();
|
|
}
|
|
|
|
trackers[index]++;
|
|
}
|
|
|
|
trackers[index] = 0;
|
|
};
|
|
|
|
if (!matrix.length) return '';
|
|
|
|
crawl();
|
|
|
|
return paths;
|
|
},
|
|
|
|
/**
|
|
* Builds up a selector string from a provided paths array.
|
|
*
|
|
* @private
|
|
* @param {Array.<Array.<string>>} paths
|
|
* @return {string}
|
|
*/
|
|
|
|
buildSelectorFromPaths: function(paths) {
|
|
var self = this,
|
|
path = null,
|
|
output = [],
|
|
pathSelector = '',
|
|
nodeDelineator = '',
|
|
i = -1;
|
|
|
|
if (!paths.length) {
|
|
return '';
|
|
}
|
|
|
|
if (self.config.multifilter.logicBetweenGroups === 'or') {
|
|
nodeDelineator = ', ';
|
|
}
|
|
|
|
if (paths.length > 1) {
|
|
for (i = 0; i < paths.length; i++) {
|
|
path = paths[i];
|
|
|
|
pathSelector = path.join(nodeDelineator);
|
|
|
|
if (output.indexOf(pathSelector) < 0) {
|
|
output.push(pathSelector);
|
|
}
|
|
}
|
|
|
|
return output.join(', ');
|
|
} else {
|
|
return paths[0].join(nodeDelineator);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Traverses the currently active filters in all groups, building up a
|
|
* compound selector string as per the defined logic. A filter operation
|
|
* is then called on the mixer using the resulting selector.
|
|
*
|
|
* This method can be used to programmatically trigger the parsing of
|
|
* filter groups after manipulations to a group's active selector(s) by
|
|
* the `.setFilterGroupSelectors()` API method.
|
|
*
|
|
* @example
|
|
*
|
|
* .parseFilterGroups([animate] [, callback])
|
|
*
|
|
* @example <caption>Example: Triggering parsing after programmatically changing the values of a filter group</caption>
|
|
*
|
|
* mixer.setFilterGroupSelectors('color', ['.green', '.blue']);
|
|
*
|
|
* mixer.parseFilterGroups();
|
|
*
|
|
* @public
|
|
* @since 3.0.0
|
|
* @param {boolean} [animate=true]
|
|
* An optional boolean dictating whether the operation should animate, or occur syncronously with no animation. `true` by default.
|
|
* @param {function} [callback=null]
|
|
* An optional callback function to be invoked after the operation has completed.
|
|
* @return {Promise.<mixitup.State>}
|
|
* A promise resolving with the current state object.
|
|
*/
|
|
|
|
parseFilterGroups: function() {
|
|
var self = this,
|
|
instruction = self.parseFilterArgs(arguments),
|
|
paths = self.getFilterGroupPaths(),
|
|
selector = self.buildSelectorFromPaths(paths),
|
|
callback = null,
|
|
command = {};
|
|
|
|
if (selector === '') {
|
|
selector = self.config.controls.toggleDefault;
|
|
}
|
|
|
|
instruction.command.selector = selector;
|
|
|
|
command.filter = instruction.command;
|
|
|
|
if (typeof (callback = self.config.callbacks.onParseFilterGroups) === 'function') {
|
|
command = callback(command);
|
|
}
|
|
|
|
return self.multimix(command, instruction.animate, instruction.callback);
|
|
},
|
|
|
|
/**
|
|
* Programmatically sets one or more active selectors for a specific filter
|
|
* group and updates the group's UI.
|
|
*
|
|
* Because MixItUp has no way of knowing how to break down a provided
|
|
* compound selector into its component groups, we can not use the
|
|
* standard `.filter()` or `toggleOn()/toggleOff()` API methods when using
|
|
* the MultiFilter extension. Instead, this method allows us to perform
|
|
* multi-dimensional filtering via the API by setting the active selectors of
|
|
* individual groups and then triggering the `.parseFilterGroups()` method.
|
|
*
|
|
* If setting multiple active selectors, do not pass a compound selector.
|
|
* Instead, pass an array with each item containing a single selector
|
|
* string as in example 2.
|
|
*
|
|
* @example
|
|
*
|
|
* .setFilterGroupSelectors(groupName, selectors)
|
|
*
|
|
* @example <caption>Example 1: Setting a single active selector for a "color" group</caption>
|
|
*
|
|
* mixer.setFilterGroupSelectors('color', '.green');
|
|
*
|
|
* mixer.parseFilterGroups();
|
|
*
|
|
* @example <caption>Example 2: Setting multiple active selectors for a "size" group</caption>
|
|
*
|
|
* mixer.setFilterGroupSelectors('size', ['.small', '.large']);
|
|
*
|
|
* mixer.parseFilterGroups();
|
|
*
|
|
* @public
|
|
* @since 3.2.0
|
|
* @param {string} groupName The name of the filter group as defined in the markup via the `data-filter-group` attribute.
|
|
* @param {(string|Array.<string>)} selectors A single selector string, or multiple selector strings as an array.
|
|
* @return {void}
|
|
*/
|
|
|
|
setFilterGroupSelectors: function(groupName, selectors) {
|
|
var self = this,
|
|
filterGroup = null;
|
|
|
|
selectors = Array.isArray(selectors) ? selectors : [selectors];
|
|
|
|
if (typeof (filterGroup = self.filterGroupsHash[groupName]) === 'undefined') {
|
|
throw new Error('[MixItUp MultiFilter] No filter group could be found with the name "' + groupName + '"');
|
|
}
|
|
|
|
filterGroup.activeToggles = selectors.slice();
|
|
|
|
if (filterGroup.logic === 'and') {
|
|
// Compress into single node
|
|
|
|
filterGroup.activeSelectors = [filterGroup.activeToggles];
|
|
} else {
|
|
filterGroup.activeSelectors = filterGroup.activeToggles;
|
|
}
|
|
|
|
filterGroup.updateUi(filterGroup.activeToggles);
|
|
},
|
|
|
|
/**
|
|
* Returns an array of active selectors for a specific filter group.
|
|
*
|
|
* @example
|
|
*
|
|
* .getFilterGroupSelectors(groupName)
|
|
*
|
|
* @example <caption>Example: Retrieving the active selectors for a "size" group</caption>
|
|
*
|
|
* mixer.getFilterGroupSelectors('size'); // ['.small', '.large']
|
|
*
|
|
* @public
|
|
* @since 3.2.0
|
|
* @param {string} groupName The name of the filter group as defined in the markup via the `data-filter-group` attribute.
|
|
* @return {void}
|
|
*/
|
|
|
|
getFilterGroupSelectors: function(groupName) {
|
|
var self = this,
|
|
filterGroup = null;
|
|
|
|
if (typeof (filterGroup = self.filterGroupsHash[groupName]) === 'undefined') {
|
|
throw new Error('[MixItUp MultiFilter] No filter group could be found with the name "' + groupName + '"');
|
|
}
|
|
|
|
return filterGroup.activeSelectors.slice();
|
|
}
|
|
});
|
|
|
|
mixitup.Facade.registerAction('afterConstruct', 'multifilter', function(mixer) {
|
|
this.parseFilterGroups = mixer.parseFilterGroups.bind(mixer);
|
|
this.setFilterGroupSelectors = mixer.setFilterGroupSelectors.bind(mixer);
|
|
this.getFilterGroupSelectors = mixer.getFilterGroupSelectors.bind(mixer);
|
|
}); };
|
|
|
|
mixitupMultifilter.TYPE = 'mixitup-extension';
|
|
mixitupMultifilter.NAME = 'mixitup-multifilter';
|
|
mixitupMultifilter.EXTENSION_VERSION = '3.3.6';
|
|
mixitupMultifilter.REQUIRE_CORE_VERSION = '^3.1.2';
|
|
|
|
if (typeof exports === 'object' && typeof module === 'object') {
|
|
module.exports = mixitupMultifilter;
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
define(function() {
|
|
return mixitupMultifilter;
|
|
});
|
|
} else if (window.mixitup && typeof window.mixitup === 'function') {
|
|
mixitupMultifilter(window.mixitup);
|
|
} else {
|
|
throw new Error('[MixItUp MultiFilter] MixItUp core not found');
|
|
}})(window); |