/**! * MixItUp v2.1.10 * * @copyright Copyright 2015 KunkaLabs Limited. * @author KunkaLabs Limited. * @link https://mixitup.kunkalabs.com * * @license Commercial use requires a commercial license. * https://mixitup.kunkalabs.com/licenses/ * * Non-commercial use permitted under terms of CC-BY-NC license. * http://creativecommons.org/licenses/by-nc/3.0/ */ (function($, undf){ 'use strict'; /** * MixItUp Constructor Function * @constructor * @extends jQuery */ $.MixItUp = function(){ var self = this; self._execAction('_constructor', 0); $.extend(self, { /* Public Properties ---------------------------------------------------------------------- */ selectors: { target: '.mix', filter: '.filter', sort: '.sort' }, animation: { enable: true, effects: 'fade scale', duration: 600, easing: 'ease', perspectiveDistance: '3000', perspectiveOrigin: '50% 50%', queue: true, queueLimit: 1, animateChangeLayout: false, animateResizeContainer: true, animateResizeTargets: false, staggerSequence: false, reverseOut: false }, callbacks: { onMixLoad: false, onMixStart: false, onMixBusy: false, onMixEnd: false, onMixFail: false, _user: false }, controls: { enable: true, live: false, toggleFilterButtons: false, toggleLogic: 'or', activeClass: 'active' }, layout: { display: 'inline-block', containerClass: '', containerClassFail: 'fail' }, load: { filter: 'all', sort: false }, /* Private Properties ---------------------------------------------------------------------- */ _$body: null, _$container: null, _$targets: null, _$parent: null, _$sortButtons: null, _$filterButtons: null, _suckMode: false, _mixing: false, _sorting: false, _clicking: false, _loading: true, _changingLayout: false, _changingClass: false, _changingDisplay: false, _origOrder: [], _startOrder: [], _newOrder: [], _activeFilter: null, _toggleArray: [], _toggleString: '', _activeSort: 'default:asc', _newSort: null, _startHeight: null, _newHeight: null, _incPadding: true, _newDisplay: null, _newClass: null, _targetsBound: 0, _targetsDone: 0, _queue: [], _$show: $(), _$hide: $() }); self._execAction('_constructor', 1); }; /** * MixItUp Prototype * @override */ $.MixItUp.prototype = { constructor: $.MixItUp, /* Static Properties ---------------------------------------------------------------------- */ _instances: {}, _handled: { _filter: {}, _sort: {} }, _bound: { _filter: {}, _sort: {} }, _actions: {}, _filters: {}, /* Static Methods ---------------------------------------------------------------------- */ /** * Extend * @since 2.1.0 * @param {object} new properties/methods * @extends {object} prototype */ extend: function(extension){ for(var key in extension){ $.MixItUp.prototype[key] = extension[key]; } }, /** * Add Action * @since 2.1.0 * @param {string} hook name * @param {string} namespace * @param {function} function to execute * @param {number} priority * @extends {object} $.MixItUp.prototype._actions */ addAction: function(hook, name, func, priority){ $.MixItUp.prototype._addHook('_actions', hook, name, func, priority); }, /** * Add Filter * @since 2.1.0 * @param {string} hook name * @param {string} namespace * @param {function} function to execute * @param {number} priority * @extends {object} $.MixItUp.prototype._filters */ addFilter: function(hook, name, func, priority){ $.MixItUp.prototype._addHook('_filters', hook, name, func, priority); }, /** * Add Hook * @since 2.1.0 * @param {string} type of hook * @param {string} hook name * @param {function} function to execute * @param {number} priority * @extends {object} $.MixItUp.prototype._filters */ _addHook: function(type, hook, name, func, priority){ var collection = $.MixItUp.prototype[type], obj = {}; priority = (priority === 1 || priority === 'post') ? 'post' : 'pre'; obj[hook] = {}; obj[hook][priority] = {}; obj[hook][priority][name] = func; $.extend(true, collection, obj); }, /* Private Methods ---------------------------------------------------------------------- */ /** * Initialise * @since 2.0.0 * @param {object} domNode * @param {object} config */ _init: function(domNode, config){ var self = this; self._execAction('_init', 0, arguments); config && $.extend(true, self, config); self._$body = $('body'); self._domNode = domNode; self._$container = $(domNode); self._$container.addClass(self.layout.containerClass); self._id = domNode.id; self._platformDetect(); self._brake = self._getPrefixedCSS('transition', 'none'); self._refresh(true); self._$parent = self._$targets.parent().length ? self._$targets.parent() : self._$container; if(self.load.sort){ self._newSort = self._parseSort(self.load.sort); self._newSortString = self.load.sort; self._activeSort = self.load.sort; self._sort(); self._printSort(); } self._activeFilter = self.load.filter === 'all' ? self.selectors.target : self.load.filter === 'none' ? '' : self.load.filter; self.controls.enable && self._bindHandlers(); if(self.controls.toggleFilterButtons){ self._buildToggleArray(); for(var i = 0; i < self._toggleArray.length; i++){ self._updateControls({filter: self._toggleArray[i], sort: self._activeSort}, true); }; } else if(self.controls.enable){ self._updateControls({filter: self._activeFilter, sort: self._activeSort}); } self._filter(); self._init = true; self._$container.data('mixItUp',self); self._execAction('_init', 1, arguments); self._buildState(); self._$targets.css(self._brake); self._goMix(self.animation.enable); }, /** * Platform Detect * @since 2.0.0 */ _platformDetect: function(){ var self = this, vendorsTrans = ['Webkit', 'Moz', 'O', 'ms'], vendorsRAF = ['webkit', 'moz'], chrome = window.navigator.appVersion.match(/Chrome\/(\d+)\./) || false, ff = typeof InstallTrigger !== 'undefined', prefix = function(el){ for (var i = 0; i < vendorsTrans.length; i++){ if (vendorsTrans[i] + 'Transition' in el.style){ return { prefix: '-'+vendorsTrans[i].toLowerCase()+'-', vendor: vendorsTrans[i] }; }; }; return 'transition' in el.style ? '' : false; }, transPrefix = prefix(self._domNode); self._execAction('_platformDetect', 0); self._chrome = chrome ? parseInt(chrome[1], 10) : false; self._ff = ff ? parseInt(window.navigator.userAgent.match(/rv:([^)]+)\)/)[1]) : false; self._prefix = transPrefix.prefix; self._vendor = transPrefix.vendor; self._suckMode = window.atob && self._prefix ? false : true; self._suckMode && (self.animation.enable = false); (self._ff && self._ff <= 4) && (self.animation.enable = false); /* Polyfills ---------------------------------------------------------------------- */ /** * window.requestAnimationFrame */ for(var x = 0; x < vendorsRAF.length && !window.requestAnimationFrame; x++){ window.requestAnimationFrame = window[vendorsRAF[x]+'RequestAnimationFrame']; } /** * Object.getPrototypeOf */ if(typeof Object.getPrototypeOf !== 'function'){ if(typeof 'test'.__proto__ === 'object'){ Object.getPrototypeOf = function(object){ return object.__proto__; }; } else { Object.getPrototypeOf = function(object){ return object.constructor.prototype; }; } } /** * Element.nextElementSibling */ if(self._domNode.nextElementSibling === undf){ Object.defineProperty(Element.prototype, 'nextElementSibling',{ get: function(){ var el = this.nextSibling; while(el){ if(el.nodeType ===1){ return el; } el = el.nextSibling; } return null; } }); } self._execAction('_platformDetect', 1); }, /** * Refresh * @since 2.0.0 * @param {boolean} init * @param {boolean} force */ _refresh: function(init, force){ var self = this; self._execAction('_refresh', 0, arguments); self._$targets = self._$container.find(self.selectors.target); for(var i = 0; i < self._$targets.length; i++){ var target = self._$targets[i]; if(target.dataset === undf || force){ target.dataset = {}; for(var j = 0; j < target.attributes.length; j++){ var attr = target.attributes[j], name = attr.name, val = attr.value; if(name.indexOf('data-') > -1){ var dataName = self._helpers._camelCase(name.substring(5,name.length)); target.dataset[dataName] = val; } } } if(target.mixParent === undf){ target.mixParent = self._id; } } if( (self._$targets.length && init) || (!self._origOrder.length && self._$targets.length) ){ self._origOrder = []; for(var i = 0; i < self._$targets.length; i++){ var target = self._$targets[i]; self._origOrder.push(target); } } self._execAction('_refresh', 1, arguments); }, /** * Bind Handlers * @since 2.0.0 */ _bindHandlers: function(){ var self = this, filters = $.MixItUp.prototype._bound._filter, sorts = $.MixItUp.prototype._bound._sort; self._execAction('_bindHandlers', 0); if(self.controls.live){ self._$body .on('click.mixItUp.'+self._id, self.selectors.sort, function(){ self._processClick($(this), 'sort'); }) .on('click.mixItUp.'+self._id, self.selectors.filter, function(){ self._processClick($(this), 'filter'); }); } else { self._$sortButtons = $(self.selectors.sort); self._$filterButtons = $(self.selectors.filter); self._$sortButtons.on('click.mixItUp.'+self._id, function(){ self._processClick($(this), 'sort'); }); self._$filterButtons.on('click.mixItUp.'+self._id, function(){ self._processClick($(this), 'filter'); }); } filters[self.selectors.filter] = (filters[self.selectors.filter] === undf) ? 1 : filters[self.selectors.filter] + 1; sorts[self.selectors.sort] = (sorts[self.selectors.sort] === undf) ? 1 : sorts[self.selectors.sort] + 1; self._execAction('_bindHandlers', 1); }, /** * Process Click * @since 2.0.0 * @param {object} $button * @param {string} type */ _processClick: function($button, type){ var self = this, trackClick = function($button, type, off){ var proto = $.MixItUp.prototype; proto._handled['_'+type][self.selectors[type]] = (proto._handled['_'+type][self.selectors[type]] === undf) ? 1 : proto._handled['_'+type][self.selectors[type]] + 1; if(proto._handled['_'+type][self.selectors[type]] === proto._bound['_'+type][self.selectors[type]]){ $button[(off ? 'remove' : 'add')+'Class'](self.controls.activeClass); delete proto._handled['_'+type][self.selectors[type]]; } }; self._execAction('_processClick', 0, arguments); if(!self._mixing || (self.animation.queue && self._queue.length < self.animation.queueLimit)){ self._clicking = true; if(type === 'sort'){ var sort = $button.attr('data-sort'); if(!$button.hasClass(self.controls.activeClass) || sort.indexOf('random') > -1){ $(self.selectors.sort).removeClass(self.controls.activeClass); trackClick($button, type); self.sort(sort); } } if(type === 'filter') { var filter = $button.attr('data-filter'), ndx, seperator = self.controls.toggleLogic === 'or' ? ',' : ''; if(!self.controls.toggleFilterButtons){ if(!$button.hasClass(self.controls.activeClass)){ $(self.selectors.filter).removeClass(self.controls.activeClass); trackClick($button, type); self.filter(filter); } } else { self._buildToggleArray(); if(!$button.hasClass(self.controls.activeClass)){ trackClick($button, type); self._toggleArray.push(filter); } else { trackClick($button, type, true); ndx = self._toggleArray.indexOf(filter); self._toggleArray.splice(ndx, 1); } self._toggleArray = $.grep(self._toggleArray,function(n){return(n);}); self._toggleString = self._toggleArray.join(seperator); self.filter(self._toggleString); } } self._execAction('_processClick', 1, arguments); } else { if(typeof self.callbacks.onMixBusy === 'function'){ self.callbacks.onMixBusy.call(self._domNode, self._state, self); } self._execAction('_processClickBusy', 1, arguments); } }, /** * Build Toggle Array * @since 2.0.0 */ _buildToggleArray: function(){ var self = this, activeFilter = self._activeFilter.replace(/\s/g, ''); self._execAction('_buildToggleArray', 0, arguments); if(self.controls.toggleLogic === 'or'){ self._toggleArray = activeFilter.split(','); } else { self._toggleArray = activeFilter.split('.'); !self._toggleArray[0] && self._toggleArray.shift(); for(var i = 0, filter; filter = self._toggleArray[i]; i++){ self._toggleArray[i] = '.'+filter; } } self._execAction('_buildToggleArray', 1, arguments); }, /** * Update Controls * @since 2.0.0 * @param {object} command * @param {boolean} multi */ _updateControls: function(command, multi){ var self = this, output = { filter: command.filter, sort: command.sort }, update = function($el, filter){ try { (multi && type === 'filter' && !(output.filter === 'none' || output.filter === '')) ? $el.filter(filter).addClass(self.controls.activeClass) : $el.removeClass(self.controls.activeClass).filter(filter).addClass(self.controls.activeClass); } catch(e) {} }, type = 'filter', $el = null; self._execAction('_updateControls', 0, arguments); (command.filter === undf) && (output.filter = self._activeFilter); (command.sort === undf) && (output.sort = self._activeSort); (output.filter === self.selectors.target) && (output.filter = 'all'); for(var i = 0; i < 2; i++){ $el = self.controls.live ? $(self.selectors[type]) : self['_$'+type+'Buttons']; $el && update($el, '[data-'+type+'="'+output[type]+'"]'); type = 'sort'; } self._execAction('_updateControls', 1, arguments); }, /** * Filter (private) * @since 2.0.0 */ _filter: function(){ var self = this; self._execAction('_filter', 0); for(var i = 0; i < self._$targets.length; i++){ var $target = $(self._$targets[i]); if($target.is(self._activeFilter)){ self._$show = self._$show.add($target); } else { self._$hide = self._$hide.add($target); } } self._execAction('_filter', 1); }, /** * Sort (private) * @since 2.0.0 */ _sort: function(){ var self = this, arrayShuffle = function(oldArray){ var newArray = oldArray.slice(), len = newArray.length, i = len; while(i--){ var p = parseInt(Math.random()*len); var t = newArray[i]; newArray[i] = newArray[p]; newArray[p] = t; }; return newArray; }; self._execAction('_sort', 0); self._startOrder = []; for(var i = 0; i < self._$targets.length; i++){ var target = self._$targets[i]; self._startOrder.push(target); } switch(self._newSort[0].sortBy){ case 'default': self._newOrder = self._origOrder; break; case 'random': self._newOrder = arrayShuffle(self._startOrder); break; case 'custom': self._newOrder = self._newSort[0].order; break; default: self._newOrder = self._startOrder.concat().sort(function(a, b){ return self._compare(a, b); }); } self._execAction('_sort', 1); }, /** * Compare Algorithm * @since 2.0.0 * @param {string|number} a * @param {string|number} b * @param {number} depth (recursion) * @return {number} */ _compare: function(a, b, depth){ depth = depth ? depth : 0; var self = this, order = self._newSort[depth].order, getData = function(el){ return el.dataset[self._newSort[depth].sortBy] || 0; }, attrA = isNaN(getData(a) * 1) ? getData(a).toLowerCase() : getData(a) * 1, attrB = isNaN(getData(b) * 1) ? getData(b).toLowerCase() : getData(b) * 1; if(attrA < attrB) return order === 'asc' ? -1 : 1; if(attrA > attrB) return order === 'asc' ? 1 : -1; if(attrA === attrB && self._newSort.length > depth+1) return self._compare(a, b, depth+1); return 0; }, /** * Print Sort * @since 2.0.0 * @param {boolean} reset */ _printSort: function(reset){ var self = this, order = reset ? self._startOrder : self._newOrder, targets = self._$parent[0].querySelectorAll(self.selectors.target), nextSibling = targets.length ? targets[targets.length -1].nextElementSibling : null, frag = document.createDocumentFragment(); self._execAction('_printSort', 0, arguments); for(var i = 0; i < targets.length; i++){ var target = targets[i], whiteSpace = target.nextSibling; if(target.style.position === 'absolute') continue; if(whiteSpace && whiteSpace.nodeName === '#text'){ self._$parent[0].removeChild(whiteSpace); } self._$parent[0].removeChild(target); } for(var i = 0; i < order.length; i++){ var el = order[i]; if(self._newSort[0].sortBy === 'default' && self._newSort[0].order === 'desc' && !reset){ var firstChild = frag.firstChild; frag.insertBefore(el, firstChild); frag.insertBefore(document.createTextNode(' '), el); } else { frag.appendChild(el); frag.appendChild(document.createTextNode(' ')); } } nextSibling ? self._$parent[0].insertBefore(frag, nextSibling) : self._$parent[0].appendChild(frag); self._execAction('_printSort', 1, arguments); }, /** * Parse Sort * @since 2.0.0 * @param {string} sortString * @return {array} newSort */ _parseSort: function(sortString){ var self = this, rules = typeof sortString === 'string' ? sortString.split(' ') : [sortString], newSort = []; for(var i = 0; i < rules.length; i++){ var rule = typeof sortString === 'string' ? rules[i].split(':') : ['custom', rules[i]], ruleObj = { sortBy: self._helpers._camelCase(rule[0]), order: rule[1] || 'asc' }; newSort.push(ruleObj); if(ruleObj.sortBy === 'default' || ruleObj.sortBy === 'random') break; } return self._execFilter('_parseSort', newSort, arguments); }, /** * Parse Effects * @since 2.0.0 * @return {object} effects */ _parseEffects: function(){ var self = this, effects = { opacity: '', transformIn: '', transformOut: '', filter: '' }, parse = function(effect, extract, reverse){ if(self.animation.effects.indexOf(effect) > -1){ if(extract){ var propIndex = self.animation.effects.indexOf(effect+'('); if(propIndex > -1){ var str = self.animation.effects.substring(propIndex), match = /\(([^)]+)\)/.exec(str), val = match[1]; return {val: val}; } } return true; } else { return false; } }, negate = function(value, invert){ if(invert){ return value.charAt(0) === '-' ? value.substr(1, value.length) : '-'+value; } else { return value; } }, buildTransform = function(key, invert){ var transforms = [ ['scale', '.01'], ['translateX', '20px'], ['translateY', '20px'], ['translateZ', '20px'], ['rotateX', '90deg'], ['rotateY', '90deg'], ['rotateZ', '180deg'], ]; for(var i = 0; i < transforms.length; i++){ var prop = transforms[i][0], def = transforms[i][1], inverted = invert && prop !== 'scale'; effects[key] += parse(prop) ? prop+'('+negate(parse(prop, true).val || def, inverted)+') ' : ''; } }; effects.opacity = parse('fade') ? parse('fade',true).val || '0' : '1'; buildTransform('transformIn'); self.animation.reverseOut ? buildTransform('transformOut', true) : (effects.transformOut = effects.transformIn); effects.transition = {}; effects.transition = self._getPrefixedCSS('transition','all '+self.animation.duration+'ms '+self.animation.easing+', opacity '+self.animation.duration+'ms linear'); self.animation.stagger = parse('stagger') ? true : false; self.animation.staggerDuration = parseInt(parse('stagger') ? (parse('stagger',true).val ? parse('stagger',true).val : 100) : 100); return self._execFilter('_parseEffects', effects); }, /** * Build State * @since 2.0.0 * @param {boolean} future * @return {object} futureState */ _buildState: function(future){ var self = this, state = {}; self._execAction('_buildState', 0); state = { activeFilter: self._activeFilter === '' ? 'none' : self._activeFilter, activeSort: future && self._newSortString ? self._newSortString : self._activeSort, fail: !self._$show.length && self._activeFilter !== '', $targets: self._$targets, $show: self._$show, $hide: self._$hide, totalTargets: self._$targets.length, totalShow: self._$show.length, totalHide: self._$hide.length, display: future && self._newDisplay ? self._newDisplay : self.layout.display }; if(future){ return self._execFilter('_buildState', state); } else { self._state = state; self._execAction('_buildState', 1); } }, /** * Go Mix * @since 2.0.0 * @param {boolean} animate */ _goMix: function(animate){ var self = this, phase1 = function(){ if(self._chrome && (self._chrome === 31)){ chromeFix(self._$parent[0]); } self._setInter(); phase2(); }, phase2 = function(){ var scrollTop = window.pageYOffset, scrollLeft = window.pageXOffset, docHeight = document.documentElement.scrollHeight; self._getInterMixData(); self._setFinal(); self._getFinalMixData(); (window.pageYOffset !== scrollTop) && window.scrollTo(scrollLeft, scrollTop); self._prepTargets(); if(window.requestAnimationFrame){ requestAnimationFrame(phase3); } else { setTimeout(function(){ phase3(); },20); } }, phase3 = function(){ self._animateTargets(); if(self._targetsBound === 0){ self._cleanUp(); } }, chromeFix = function(grid){ var parent = grid.parentElement, placeholder = document.createElement('div'), frag = document.createDocumentFragment(); parent.insertBefore(placeholder, grid); frag.appendChild(grid); parent.replaceChild(grid, placeholder); }, futureState = self._buildState(true); self._execAction('_goMix', 0, arguments); !self.animation.duration && (animate = false); self._mixing = true; self._$container.removeClass(self.layout.containerClassFail); if(typeof self.callbacks.onMixStart === 'function'){ self.callbacks.onMixStart.call(self._domNode, self._state, futureState, self); } self._$container.trigger('mixStart', [self._state, futureState, self]); self._getOrigMixData(); if(animate && !self._suckMode){ window.requestAnimationFrame ? requestAnimationFrame(phase1) : phase1(); } else { self._cleanUp(); } self._execAction('_goMix', 1, arguments); }, /** * Get Target Data * @since 2.0.0 */ _getTargetData: function(el, stage){ var self = this, elStyle; el.dataset[stage+'PosX'] = el.offsetLeft; el.dataset[stage+'PosY'] = el.offsetTop; if(self.animation.animateResizeTargets){ elStyle = !self._suckMode ? window.getComputedStyle(el) : { marginBottom: '', marginRight: '' }; el.dataset[stage+'MarginBottom'] = parseInt(elStyle.marginBottom); el.dataset[stage+'MarginRight'] = parseInt(elStyle.marginRight); el.dataset[stage+'Width'] = el.offsetWidth; el.dataset[stage+'Height'] = el.offsetHeight; } }, /** * Get Original Mix Data * @since 2.0.0 */ _getOrigMixData: function(){ var self = this, parentStyle = !self._suckMode ? window.getComputedStyle(self._$parent[0]) : {boxSizing: ''}, parentBS = parentStyle.boxSizing || parentStyle[self._vendor+'BoxSizing']; self._incPadding = (parentBS === 'border-box'); self._execAction('_getOrigMixData', 0); !self._suckMode && (self.effects = self._parseEffects()); self._$toHide = self._$hide.filter(':visible'); self._$toShow = self._$show.filter(':hidden'); self._$pre = self._$targets.filter(':visible'); self._startHeight = self._incPadding ? self._$parent.outerHeight() : self._$parent.height(); for(var i = 0; i < self._$pre.length; i++){ var el = self._$pre[i]; self._getTargetData(el, 'orig'); } self._execAction('_getOrigMixData', 1); }, /** * Set Intermediate Positions * @since 2.0.0 */ _setInter: function(){ var self = this; self._execAction('_setInter', 0); if(self._changingLayout && self.animation.animateChangeLayout){ self._$toShow.css('display',self._newDisplay); if(self._changingClass){ self._$container .removeClass(self.layout.containerClass) .addClass(self._newClass); } } else { self._$toShow.css('display', self.layout.display); } self._execAction('_setInter', 1); }, /** * Get Intermediate Mix Data * @since 2.0.0 */ _getInterMixData: function(){ var self = this; self._execAction('_getInterMixData', 0); for(var i = 0; i < self._$toShow.length; i++){ var el = self._$toShow[i]; self._getTargetData(el, 'inter'); } for(var i = 0; i < self._$pre.length; i++){ var el = self._$pre[i]; self._getTargetData(el, 'inter'); } self._execAction('_getInterMixData', 1); }, /** * Set Final Positions * @since 2.0.0 */ _setFinal: function(){ var self = this; self._execAction('_setFinal', 0); self._sorting && self._printSort(); self._$toHide.removeStyle('display'); if(self._changingLayout && self.animation.animateChangeLayout){ self._$pre.css('display',self._newDisplay); } self._execAction('_setFinal', 1); }, /** * Get Final Mix Data * @since 2.0.0 */ _getFinalMixData: function(){ var self = this; self._execAction('_getFinalMixData', 0); for(var i = 0; i < self._$toShow.length; i++){ var el = self._$toShow[i]; self._getTargetData(el, 'final'); } for(var i = 0; i < self._$pre.length; i++){ var el = self._$pre[i]; self._getTargetData(el, 'final'); } self._newHeight = self._incPadding ? self._$parent.outerHeight() : self._$parent.height(); self._sorting && self._printSort(true); self._$toShow.removeStyle('display'); self._$pre.css('display',self.layout.display); if(self._changingClass && self.animation.animateChangeLayout){ self._$container .removeClass(self._newClass) .addClass(self.layout.containerClass); } self._execAction('_getFinalMixData', 1); }, /** * Prepare Targets * @since 2.0.0 */ _prepTargets: function(){ var self = this, transformCSS = { _in: self._getPrefixedCSS('transform', self.effects.transformIn), _out: self._getPrefixedCSS('transform', self.effects.transformOut) }; self._execAction('_prepTargets', 0); if(self.animation.animateResizeContainer){ self._$parent.css('height',self._startHeight+'px'); } for(var i = 0; i < self._$toShow.length; i++){ var el = self._$toShow[i], $el = $(el); el.style.opacity = self.effects.opacity; el.style.display = (self._changingLayout && self.animation.animateChangeLayout) ? self._newDisplay : self.layout.display; $el.css(transformCSS._in); if(self.animation.animateResizeTargets){ el.style.width = el.dataset.finalWidth+'px'; el.style.height = el.dataset.finalHeight+'px'; el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth) + (el.dataset.finalMarginRight * 1)+'px'; el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight) + (el.dataset.finalMarginBottom * 1)+'px'; } } for(var i = 0; i < self._$pre.length; i++){ var el = self._$pre[i], $el = $(el), translate = { x: el.dataset.origPosX - el.dataset.interPosX, y: el.dataset.origPosY - el.dataset.interPosY }, transformCSS = self._getPrefixedCSS('transform','translate('+translate.x+'px,'+translate.y+'px)'); $el.css(transformCSS); if(self.animation.animateResizeTargets){ el.style.width = el.dataset.origWidth+'px'; el.style.height = el.dataset.origHeight+'px'; if(el.dataset.origWidth - el.dataset.finalWidth){ el.style.marginRight = -(el.dataset.origWidth - el.dataset.interWidth) + (el.dataset.origMarginRight * 1)+'px'; } if(el.dataset.origHeight - el.dataset.finalHeight){ el.style.marginBottom = -(el.dataset.origHeight - el.dataset.interHeight) + (el.dataset.origMarginBottom * 1) +'px'; } } } self._execAction('_prepTargets', 1); }, /** * Animate Targets * @since 2.0.0 */ _animateTargets: function(){ var self = this; self._execAction('_animateTargets', 0); self._targetsDone = 0; self._targetsBound = 0; self._$parent .css(self._getPrefixedCSS('perspective', self.animation.perspectiveDistance+'px')) .css(self._getPrefixedCSS('perspective-origin', self.animation.perspectiveOrigin)); if(self.animation.animateResizeContainer){ self._$parent .css(self._getPrefixedCSS('transition','height '+self.animation.duration+'ms ease')) .css('height',self._newHeight+'px'); } for(var i = 0; i < self._$toShow.length; i++){ var el = self._$toShow[i], $el = $(el), translate = { x: el.dataset.finalPosX - el.dataset.interPosX, y: el.dataset.finalPosY - el.dataset.interPosY }, delay = self._getDelay(i), toShowCSS = {}; el.style.opacity = ''; for(var j = 0; j < 2; j++){ var a = j === 0 ? a = self._prefix : ''; if(self._ff && self._ff <= 20){ toShowCSS[a+'transition-property'] = 'all'; toShowCSS[a+'transition-timing-function'] = self.animation.easing+'ms'; toShowCSS[a+'transition-duration'] = self.animation.duration+'ms'; } toShowCSS[a+'transition-delay'] = delay+'ms'; toShowCSS[a+'transform'] = 'translate('+translate.x+'px,'+translate.y+'px)'; } if(self.effects.transform || self.effects.opacity){ self._bindTargetDone($el); } (self._ff && self._ff <= 20) ? $el.css(toShowCSS) : $el.css(self.effects.transition).css(toShowCSS); } for(var i = 0; i < self._$pre.length; i++){ var el = self._$pre[i], $el = $(el), translate = { x: el.dataset.finalPosX - el.dataset.interPosX, y: el.dataset.finalPosY - el.dataset.interPosY }, delay = self._getDelay(i); if(!( el.dataset.finalPosX === el.dataset.origPosX && el.dataset.finalPosY === el.dataset.origPosY )){ self._bindTargetDone($el); } $el.css(self._getPrefixedCSS('transition', 'all '+self.animation.duration+'ms '+self.animation.easing+' '+delay+'ms')); $el.css(self._getPrefixedCSS('transform', 'translate('+translate.x+'px,'+translate.y+'px)')); if(self.animation.animateResizeTargets){ if(el.dataset.origWidth - el.dataset.finalWidth && el.dataset.finalWidth * 1){ el.style.width = el.dataset.finalWidth+'px'; el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth)+(el.dataset.finalMarginRight * 1)+'px'; } if(el.dataset.origHeight - el.dataset.finalHeight && el.dataset.finalHeight * 1){ el.style.height = el.dataset.finalHeight+'px'; el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight)+(el.dataset.finalMarginBottom * 1) +'px'; } } } if(self._changingClass){ self._$container .removeClass(self.layout.containerClass) .addClass(self._newClass); } for(var i = 0; i < self._$toHide.length; i++){ var el = self._$toHide[i], $el = $(el), delay = self._getDelay(i), toHideCSS = {}; for(var j = 0; j<2; j++){ var a = j === 0 ? a = self._prefix : ''; toHideCSS[a+'transition-delay'] = delay+'ms'; toHideCSS[a+'transform'] = self.effects.transformOut; toHideCSS.opacity = self.effects.opacity; } $el.css(self.effects.transition).css(toHideCSS); if(self.effects.transform || self.effects.opacity){ self._bindTargetDone($el); }; } self._execAction('_animateTargets', 1); }, /** * Bind Targets TransitionEnd * @since 2.0.0 * @param {object} $el */ _bindTargetDone: function($el){ var self = this, el = $el[0]; self._execAction('_bindTargetDone', 0, arguments); if(!el.dataset.bound){ el.dataset.bound = true; self._targetsBound++; $el.on('webkitTransitionEnd.mixItUp transitionend.mixItUp',function(e){ if( (e.originalEvent.propertyName.indexOf('transform') > -1 || e.originalEvent.propertyName.indexOf('opacity') > -1) && $(e.originalEvent.target).is(self.selectors.target) ){ $el.off('.mixItUp'); delete el.dataset.bound; self._targetDone(); } }); } self._execAction('_bindTargetDone', 1, arguments); }, /** * Target Done * @since 2.0.0 */ _targetDone: function(){ var self = this; self._execAction('_targetDone', 0); self._targetsDone++; (self._targetsDone === self._targetsBound) && self._cleanUp(); self._execAction('_targetDone', 1); }, /** * Clean Up * @since 2.0.0 */ _cleanUp: function(){ var self = this, targetStyles = self.animation.animateResizeTargets ? 'transform opacity width height margin-bottom margin-right' : 'transform opacity', unBrake = function(){ self._$targets.removeStyle('transition', self._prefix); }; self._execAction('_cleanUp', 0); !self._changingLayout ? self._$show.css('display',self.layout.display) : self._$show.css('display',self._newDisplay); self._$targets.css(self._brake); self._$targets .removeStyle(targetStyles, self._prefix) .removeAttr('data-inter-pos-x data-inter-pos-y data-final-pos-x data-final-pos-y data-orig-pos-x data-orig-pos-y data-orig-height data-orig-width data-final-height data-final-width data-inter-width data-inter-height data-orig-margin-right data-orig-margin-bottom data-inter-margin-right data-inter-margin-bottom data-final-margin-right data-final-margin-bottom'); self._$hide.removeStyle('display'); self._$parent.removeStyle('height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin', self._prefix); if(self._sorting){ self._printSort(); self._activeSort = self._newSortString; self._sorting = false; } if(self._changingLayout){ if(self._changingDisplay){ self.layout.display = self._newDisplay; self._changingDisplay = false; } if(self._changingClass){ self._$parent.removeClass(self.layout.containerClass).addClass(self._newClass); self.layout.containerClass = self._newClass; self._changingClass = false; } self._changingLayout = false; } self._refresh(); self._buildState(); if(self._state.fail){ self._$container.addClass(self.layout.containerClassFail); } self._$show = $(); self._$hide = $(); if(window.requestAnimationFrame){ requestAnimationFrame(unBrake); } self._mixing = false; if(typeof self.callbacks._user === 'function'){ self.callbacks._user.call(self._domNode, self._state, self); } if(typeof self.callbacks.onMixEnd === 'function'){ self.callbacks.onMixEnd.call(self._domNode, self._state, self); } self._$container.trigger('mixEnd', [self._state, self]); if(self._state.fail){ (typeof self.callbacks.onMixFail === 'function') && self.callbacks.onMixFail.call(self._domNode, self._state, self); self._$container.trigger('mixFail', [self._state, self]); } if(self._loading){ (typeof self.callbacks.onMixLoad === 'function') && self.callbacks.onMixLoad.call(self._domNode, self._state, self); self._$container.trigger('mixLoad', [self._state, self]); } if(self._queue.length){ self._execAction('_queue', 0); self.multiMix(self._queue[0][0],self._queue[0][1],self._queue[0][2]); self._queue.splice(0, 1); } self._execAction('_cleanUp', 1); self._loading = false; }, /** * Get Prefixed CSS * @since 2.0.0 * @param {string} property * @param {string} value * @param {boolean} prefixValue * @return {object} styles */ _getPrefixedCSS: function(property, value, prefixValue){ var self = this, styles = {}, prefix = '', i = -1; for(i = 0; i < 2; i++){ prefix = i === 0 ? self._prefix : ''; prefixValue ? styles[prefix+property] = prefix+value : styles[prefix+property] = value; } return self._execFilter('_getPrefixedCSS', styles, arguments); }, /** * Get Delay * @since 2.0.0 * @param {number} i * @return {number} delay */ _getDelay: function(i){ var self = this, n = typeof self.animation.staggerSequence === 'function' ? self.animation.staggerSequence.call(self._domNode, i, self._state) : i, delay = self.animation.stagger ? n * self.animation.staggerDuration : 0; return self._execFilter('_getDelay', delay, arguments); }, /** * Parse MultiMix Arguments * @since 2.0.0 * @param {array} args * @return {object} output */ _parseMultiMixArgs: function(args){ var self = this, output = { command: null, animate: self.animation.enable, callback: null }; for(var i = 0; i < args.length; i++){ var arg = args[i]; if(arg !== null){ if(typeof arg === 'object' || typeof arg === 'string'){ output.command = arg; } else if(typeof arg === 'boolean'){ output.animate = arg; } else if(typeof arg === 'function'){ output.callback = arg; } } } return self._execFilter('_parseMultiMixArgs', output, arguments); }, /** * Parse Insert Arguments * @since 2.0.0 * @param {array} args * @return {object} output */ _parseInsertArgs: function(args){ var self = this, output = { index: 0, $object: $(), multiMix: {filter: self._state.activeFilter}, callback: null }; for(var i = 0; i < args.length; i++){ var arg = args[i]; if(typeof arg === 'number'){ output.index = arg; } else if(typeof arg === 'object' && arg instanceof $){ output.$object = arg; } else if(typeof arg === 'object' && self._helpers._isElement(arg)){ output.$object = $(arg); } else if(typeof arg === 'object' && arg !== null){ output.multiMix = arg; } else if(typeof arg === 'boolean' && !arg){ output.multiMix = false; } else if(typeof arg === 'function'){ output.callback = arg; } } return self._execFilter('_parseInsertArgs', output, arguments); }, /** * Execute Action * @since 2.0.0 * @param {string} methodName * @param {boolean} isPost * @param {array} args */ _execAction: function(methodName, isPost, args){ var self = this, context = isPost ? 'post' : 'pre'; if(!self._actions.isEmptyObject && self._actions.hasOwnProperty(methodName)){ for(var key in self._actions[methodName][context]){ self._actions[methodName][context][key].call(self, args); } } }, /** * Execute Filter * @since 2.0.0 * @param {string} methodName * @param {mixed} value * @return {mixed} value */ _execFilter: function(methodName, value, args){ var self = this; if(!self._filters.isEmptyObject && self._filters.hasOwnProperty(methodName)){ for(var key in self._filters[methodName]){ return self._filters[methodName][key].call(self, args); } } else { return value; } }, /* Helpers ---------------------------------------------------------------------- */ _helpers: { /** * CamelCase * @since 2.0.0 * @param {string} * @return {string} */ _camelCase: function(string){ return string.replace(/-([a-z])/g, function(g){ return g[1].toUpperCase(); }); }, /** * Is Element * @since 2.1.3 * @param {object} element to test * @return {boolean} */ _isElement: function(el){ if(window.HTMLElement){ return el instanceof HTMLElement; } else { return ( el !== null && el.nodeType === 1 && el.nodeName === 'string' ); } } }, /* Public Methods ---------------------------------------------------------------------- */ /** * Is Mixing * @since 2.0.0 * @return {boolean} */ isMixing: function(){ var self = this; return self._execFilter('isMixing', self._mixing); }, /** * Filter (public) * @since 2.0.0 * @param {array} arguments */ filter: function(){ var self = this, args = self._parseMultiMixArgs(arguments); self._clicking && (self._toggleString = ''); self.multiMix({filter: args.command}, args.animate, args.callback); }, /** * Sort (public) * @since 2.0.0 * @param {array} arguments */ sort: function(){ var self = this, args = self._parseMultiMixArgs(arguments); self.multiMix({sort: args.command}, args.animate, args.callback); }, /** * Change Layout (public) * @since 2.0.0 * @param {array} arguments */ changeLayout: function(){ var self = this, args = self._parseMultiMixArgs(arguments); self.multiMix({changeLayout: args.command}, args.animate, args.callback); }, /** * MultiMix * @since 2.0.0 * @param {array} arguments */ multiMix: function(){ var self = this, args = self._parseMultiMixArgs(arguments); self._execAction('multiMix', 0, arguments); if(!self._mixing){ if(self.controls.enable && !self._clicking){ self.controls.toggleFilterButtons && self._buildToggleArray(); self._updateControls(args.command, self.controls.toggleFilterButtons); } (self._queue.length < 2) && (self._clicking = false); delete self.callbacks._user; if(args.callback) self.callbacks._user = args.callback; var sort = args.command.sort, filter = args.command.filter, changeLayout = args.command.changeLayout; self._refresh(); if(sort){ self._newSort = self._parseSort(sort); self._newSortString = sort; self._sorting = true; self._sort(); } if(filter !== undf){ filter = (filter === 'all') ? self.selectors.target : filter; self._activeFilter = filter; } self._filter(); if(changeLayout){ self._newDisplay = (typeof changeLayout === 'string') ? changeLayout : changeLayout.display || self.layout.display; self._newClass = changeLayout.containerClass || ''; if( self._newDisplay !== self.layout.display || self._newClass !== self.layout.containerClass ){ self._changingLayout = true; self._changingClass = (self._newClass !== self.layout.containerClass); self._changingDisplay = (self._newDisplay !== self.layout.display); } } self._$targets.css(self._brake); self._goMix(args.animate ^ self.animation.enable ? args.animate : self.animation.enable); self._execAction('multiMix', 1, arguments); } else { if(self.animation.queue && self._queue.length < self.animation.queueLimit){ self._queue.push(arguments); (self.controls.enable && !self._clicking) && self._updateControls(args.command); self._execAction('multiMixQueue', 1, arguments); } else { if(typeof self.callbacks.onMixBusy === 'function'){ self.callbacks.onMixBusy.call(self._domNode, self._state, self); } self._$container.trigger('mixBusy', [self._state, self]); self._execAction('multiMixBusy', 1, arguments); } } }, /** * Insert * @since 2.0.0 * @param {array} arguments */ insert: function(){ var self = this, args = self._parseInsertArgs(arguments), callback = (typeof args.callback === 'function') ? args.callback : null, frag = document.createDocumentFragment(), target = (function(){ self._refresh(); if(self._$targets.length){ return (args.index < self._$targets.length || !self._$targets.length) ? self._$targets[args.index] : self._$targets[self._$targets.length-1].nextElementSibling; } else { return self._$parent[0].children[0]; } })(); self._execAction('insert', 0, arguments); if(args.$object){ for(var i = 0; i < args.$object.length; i++){ var el = args.$object[i]; frag.appendChild(el); frag.appendChild(document.createTextNode(' ')); } self._$parent[0].insertBefore(frag, target); } self._execAction('insert', 1, arguments); if(typeof args.multiMix === 'object'){ self.multiMix(args.multiMix, callback); } }, /** * Prepend * @since 2.0.0 * @param {array} arguments */ prepend: function(){ var self = this, args = self._parseInsertArgs(arguments); self.insert(0, args.$object, args.multiMix, args.callback); }, /** * Append * @since 2.0.0 * @param {array} arguments */ append: function(){ var self = this, args = self._parseInsertArgs(arguments); self.insert(self._state.totalTargets, args.$object, args.multiMix, args.callback); }, /** * Get Option * @since 2.0.0 * @param {string} string * @return {mixed} value */ getOption: function(string){ var self = this, getProperty = function(obj, prop){ var parts = prop.split('.'), last = parts.pop(), l = parts.length, i = 1, current = parts[0] || prop; while((obj = obj[current]) && i < l){ current = parts[i]; i++; } if(obj !== undf){ return obj[last] !== undf ? obj[last] : obj; } }; return string ? self._execFilter('getOption', getProperty(self, string), arguments) : self; }, /** * Set Options * @since 2.0.0 * @param {object} config */ setOptions: function(config){ var self = this; self._execAction('setOptions', 0, arguments); typeof config === 'object' && $.extend(true, self, config); self._execAction('setOptions', 1, arguments); }, /** * Get State * @since 2.0.0 * @return {object} state */ getState: function(){ var self = this; return self._execFilter('getState', self._state, self); }, /** * Force Refresh * @since 2.1.2 */ forceRefresh: function(){ var self = this; self._refresh(false, true); }, /** * Destroy * @since 2.0.0 * @param {boolean} hideAll */ destroy: function(hideAll){ var self = this, filters = $.MixItUp.prototype._bound._filter, sorts = $.MixItUp.prototype._bound._sort; self._execAction('destroy', 0, arguments); self._$body .add($(self.selectors.sort)) .add($(self.selectors.filter)) .off('.mixItUp'); for(var i = 0; i < self._$targets.length; i++){ var target = self._$targets[i]; hideAll && (target.style.display = ''); delete target.mixParent; } self._execAction('destroy', 1, arguments); if(filters[self.selectors.filter] && filters[self.selectors.filter] > 1) { filters[self.selectors.filter]--; } else if(filters[self.selectors.filter] === 1) { delete filters[self.selectors.filter]; } if(sorts[self.selectors.sort] && sorts[self.selectors.sort] > 1) { sorts[self.selectors.sort]--; } else if(sorts[self.selectors.sort] === 1) { delete sorts[self.selectors.sort]; } delete $.MixItUp.prototype._instances[self._id]; } }; /* jQuery Methods ---------------------------------------------------------------------- */ /** * jQuery .mixItUp() method * @since 2.0.0 * @extends $.fn */ $.fn.mixItUp = function(){ var args = arguments, dataReturn = [], eachReturn, _instantiate = function(domNode, settings){ var instance = new $.MixItUp(), rand = function(){ return ('00000'+(Math.random()*16777216<<0).toString(16)).substr(-6).toUpperCase(); }; instance._execAction('_instantiate', 0, arguments); domNode.id = !domNode.id ? 'MixItUp'+rand() : domNode.id; if(!instance._instances[domNode.id]){ instance._instances[domNode.id] = instance; instance._init(domNode, settings); } instance._execAction('_instantiate', 1, arguments); }; eachReturn = this.each(function(){ if(args && typeof args[0] === 'string'){ var instance = $.MixItUp.prototype._instances[this.id]; if(args[0] === 'isLoaded'){ dataReturn.push(instance ? true : false); } else { var data = instance[args[0]](args[1], args[2], args[3]); if(data !== undf)dataReturn.push(data); } } else { _instantiate(this, args[0]); } }); if(dataReturn.length){ return dataReturn.length > 1 ? dataReturn : dataReturn[0]; } else { return eachReturn; } }; /** * jQuery .removeStyle() method * @since 2.0.0 * @extends $.fn */ $.fn.removeStyle = function(style, prefix){ prefix = prefix ? prefix : ''; return this.each(function(){ var el = this, styles = style.split(' '); for(var i = 0; i < styles.length; i++){ for(var j = 0; j < 4; j++){ switch (j) { case 0: var prop = styles[i]; break; case 1: var prop = $.MixItUp.prototype._helpers._camelCase(prop); break; case 2: var prop = prefix+styles[i]; break; case 3: var prop = $.MixItUp.prototype._helpers._camelCase(prefix+styles[i]); } if( el.style[prop] !== undf && typeof el.style[prop] !== 'unknown' && el.style[prop].length > 0 ){ el.style[prop] = ''; } if(!prefix && j === 1)break; } } if(el.attributes && el.attributes.style && el.attributes.style !== undf && el.attributes.style.value === ''){ el.attributes.removeNamedItem('style'); } }); }; })(jQuery);