Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

2 роки тому
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098
  1. /**!
  2. * MixItUp v2.1.10
  3. *
  4. * @copyright Copyright 2015 KunkaLabs Limited.
  5. * @author KunkaLabs Limited.
  6. * @link https://mixitup.kunkalabs.com
  7. *
  8. * @license Commercial use requires a commercial license.
  9. * https://mixitup.kunkalabs.com/licenses/
  10. *
  11. * Non-commercial use permitted under terms of CC-BY-NC license.
  12. * http://creativecommons.org/licenses/by-nc/3.0/
  13. */
  14. (function($, undf){
  15. 'use strict';
  16. /**
  17. * MixItUp Constructor Function
  18. * @constructor
  19. * @extends jQuery
  20. */
  21. $.MixItUp = function(){
  22. var self = this;
  23. self._execAction('_constructor', 0);
  24. $.extend(self, {
  25. /* Public Properties
  26. ---------------------------------------------------------------------- */
  27. selectors: {
  28. target: '.mix',
  29. filter: '.filter',
  30. sort: '.sort'
  31. },
  32. animation: {
  33. enable: true,
  34. effects: 'fade scale',
  35. duration: 600,
  36. easing: 'ease',
  37. perspectiveDistance: '3000',
  38. perspectiveOrigin: '50% 50%',
  39. queue: true,
  40. queueLimit: 1,
  41. animateChangeLayout: false,
  42. animateResizeContainer: true,
  43. animateResizeTargets: false,
  44. staggerSequence: false,
  45. reverseOut: false
  46. },
  47. callbacks: {
  48. onMixLoad: false,
  49. onMixStart: false,
  50. onMixBusy: false,
  51. onMixEnd: false,
  52. onMixFail: false,
  53. _user: false
  54. },
  55. controls: {
  56. enable: true,
  57. live: false,
  58. toggleFilterButtons: false,
  59. toggleLogic: 'or',
  60. activeClass: 'active'
  61. },
  62. layout: {
  63. display: 'inline-block',
  64. containerClass: '',
  65. containerClassFail: 'fail'
  66. },
  67. load: {
  68. filter: 'all',
  69. sort: false
  70. },
  71. /* Private Properties
  72. ---------------------------------------------------------------------- */
  73. _$body: null,
  74. _$container: null,
  75. _$targets: null,
  76. _$parent: null,
  77. _$sortButtons: null,
  78. _$filterButtons: null,
  79. _suckMode: false,
  80. _mixing: false,
  81. _sorting: false,
  82. _clicking: false,
  83. _loading: true,
  84. _changingLayout: false,
  85. _changingClass: false,
  86. _changingDisplay: false,
  87. _origOrder: [],
  88. _startOrder: [],
  89. _newOrder: [],
  90. _activeFilter: null,
  91. _toggleArray: [],
  92. _toggleString: '',
  93. _activeSort: 'default:asc',
  94. _newSort: null,
  95. _startHeight: null,
  96. _newHeight: null,
  97. _incPadding: true,
  98. _newDisplay: null,
  99. _newClass: null,
  100. _targetsBound: 0,
  101. _targetsDone: 0,
  102. _queue: [],
  103. _$show: $(),
  104. _$hide: $()
  105. });
  106. self._execAction('_constructor', 1);
  107. };
  108. /**
  109. * MixItUp Prototype
  110. * @override
  111. */
  112. $.MixItUp.prototype = {
  113. constructor: $.MixItUp,
  114. /* Static Properties
  115. ---------------------------------------------------------------------- */
  116. _instances: {},
  117. _handled: {
  118. _filter: {},
  119. _sort: {}
  120. },
  121. _bound: {
  122. _filter: {},
  123. _sort: {}
  124. },
  125. _actions: {},
  126. _filters: {},
  127. /* Static Methods
  128. ---------------------------------------------------------------------- */
  129. /**
  130. * Extend
  131. * @since 2.1.0
  132. * @param {object} new properties/methods
  133. * @extends {object} prototype
  134. */
  135. extend: function(extension){
  136. for(var key in extension){
  137. $.MixItUp.prototype[key] = extension[key];
  138. }
  139. },
  140. /**
  141. * Add Action
  142. * @since 2.1.0
  143. * @param {string} hook name
  144. * @param {string} namespace
  145. * @param {function} function to execute
  146. * @param {number} priority
  147. * @extends {object} $.MixItUp.prototype._actions
  148. */
  149. addAction: function(hook, name, func, priority){
  150. $.MixItUp.prototype._addHook('_actions', hook, name, func, priority);
  151. },
  152. /**
  153. * Add Filter
  154. * @since 2.1.0
  155. * @param {string} hook name
  156. * @param {string} namespace
  157. * @param {function} function to execute
  158. * @param {number} priority
  159. * @extends {object} $.MixItUp.prototype._filters
  160. */
  161. addFilter: function(hook, name, func, priority){
  162. $.MixItUp.prototype._addHook('_filters', hook, name, func, priority);
  163. },
  164. /**
  165. * Add Hook
  166. * @since 2.1.0
  167. * @param {string} type of hook
  168. * @param {string} hook name
  169. * @param {function} function to execute
  170. * @param {number} priority
  171. * @extends {object} $.MixItUp.prototype._filters
  172. */
  173. _addHook: function(type, hook, name, func, priority){
  174. var collection = $.MixItUp.prototype[type],
  175. obj = {};
  176. priority = (priority === 1 || priority === 'post') ? 'post' : 'pre';
  177. obj[hook] = {};
  178. obj[hook][priority] = {};
  179. obj[hook][priority][name] = func;
  180. $.extend(true, collection, obj);
  181. },
  182. /* Private Methods
  183. ---------------------------------------------------------------------- */
  184. /**
  185. * Initialise
  186. * @since 2.0.0
  187. * @param {object} domNode
  188. * @param {object} config
  189. */
  190. _init: function(domNode, config){
  191. var self = this;
  192. self._execAction('_init', 0, arguments);
  193. config && $.extend(true, self, config);
  194. self._$body = $('body');
  195. self._domNode = domNode;
  196. self._$container = $(domNode);
  197. self._$container.addClass(self.layout.containerClass);
  198. self._id = domNode.id;
  199. self._platformDetect();
  200. self._brake = self._getPrefixedCSS('transition', 'none');
  201. self._refresh(true);
  202. self._$parent = self._$targets.parent().length ? self._$targets.parent() : self._$container;
  203. if(self.load.sort){
  204. self._newSort = self._parseSort(self.load.sort);
  205. self._newSortString = self.load.sort;
  206. self._activeSort = self.load.sort;
  207. self._sort();
  208. self._printSort();
  209. }
  210. self._activeFilter = self.load.filter === 'all' ?
  211. self.selectors.target :
  212. self.load.filter === 'none' ?
  213. '' :
  214. self.load.filter;
  215. self.controls.enable && self._bindHandlers();
  216. if(self.controls.toggleFilterButtons){
  217. self._buildToggleArray();
  218. for(var i = 0; i < self._toggleArray.length; i++){
  219. self._updateControls({filter: self._toggleArray[i], sort: self._activeSort}, true);
  220. };
  221. } else if(self.controls.enable){
  222. self._updateControls({filter: self._activeFilter, sort: self._activeSort});
  223. }
  224. self._filter();
  225. self._init = true;
  226. self._$container.data('mixItUp',self);
  227. self._execAction('_init', 1, arguments);
  228. self._buildState();
  229. self._$targets.css(self._brake);
  230. self._goMix(self.animation.enable);
  231. },
  232. /**
  233. * Platform Detect
  234. * @since 2.0.0
  235. */
  236. _platformDetect: function(){
  237. var self = this,
  238. vendorsTrans = ['Webkit', 'Moz', 'O', 'ms'],
  239. vendorsRAF = ['webkit', 'moz'],
  240. chrome = window.navigator.appVersion.match(/Chrome\/(\d+)\./) || false,
  241. ff = typeof InstallTrigger !== 'undefined',
  242. prefix = function(el){
  243. for (var i = 0; i < vendorsTrans.length; i++){
  244. if (vendorsTrans[i] + 'Transition' in el.style){
  245. return {
  246. prefix: '-'+vendorsTrans[i].toLowerCase()+'-',
  247. vendor: vendorsTrans[i]
  248. };
  249. };
  250. };
  251. return 'transition' in el.style ? '' : false;
  252. },
  253. transPrefix = prefix(self._domNode);
  254. self._execAction('_platformDetect', 0);
  255. self._chrome = chrome ? parseInt(chrome[1], 10) : false;
  256. self._ff = ff ? parseInt(window.navigator.userAgent.match(/rv:([^)]+)\)/)[1]) : false;
  257. self._prefix = transPrefix.prefix;
  258. self._vendor = transPrefix.vendor;
  259. self._suckMode = window.atob && self._prefix ? false : true;
  260. self._suckMode && (self.animation.enable = false);
  261. (self._ff && self._ff <= 4) && (self.animation.enable = false);
  262. /* Polyfills
  263. ---------------------------------------------------------------------- */
  264. /**
  265. * window.requestAnimationFrame
  266. */
  267. for(var x = 0; x < vendorsRAF.length && !window.requestAnimationFrame; x++){
  268. window.requestAnimationFrame = window[vendorsRAF[x]+'RequestAnimationFrame'];
  269. }
  270. /**
  271. * Object.getPrototypeOf
  272. */
  273. if(typeof Object.getPrototypeOf !== 'function'){
  274. if(typeof 'test'.__proto__ === 'object'){
  275. Object.getPrototypeOf = function(object){
  276. return object.__proto__;
  277. };
  278. } else {
  279. Object.getPrototypeOf = function(object){
  280. return object.constructor.prototype;
  281. };
  282. }
  283. }
  284. /**
  285. * Element.nextElementSibling
  286. */
  287. if(self._domNode.nextElementSibling === undf){
  288. Object.defineProperty(Element.prototype, 'nextElementSibling',{
  289. get: function(){
  290. var el = this.nextSibling;
  291. while(el){
  292. if(el.nodeType ===1){
  293. return el;
  294. }
  295. el = el.nextSibling;
  296. }
  297. return null;
  298. }
  299. });
  300. }
  301. self._execAction('_platformDetect', 1);
  302. },
  303. /**
  304. * Refresh
  305. * @since 2.0.0
  306. * @param {boolean} init
  307. * @param {boolean} force
  308. */
  309. _refresh: function(init, force){
  310. var self = this;
  311. self._execAction('_refresh', 0, arguments);
  312. self._$targets = self._$container.find(self.selectors.target);
  313. for(var i = 0; i < self._$targets.length; i++){
  314. var target = self._$targets[i];
  315. if(target.dataset === undf || force){
  316. target.dataset = {};
  317. for(var j = 0; j < target.attributes.length; j++){
  318. var attr = target.attributes[j],
  319. name = attr.name,
  320. val = attr.value;
  321. if(name.indexOf('data-') > -1){
  322. var dataName = self._helpers._camelCase(name.substring(5,name.length));
  323. target.dataset[dataName] = val;
  324. }
  325. }
  326. }
  327. if(target.mixParent === undf){
  328. target.mixParent = self._id;
  329. }
  330. }
  331. if(
  332. (self._$targets.length && init) ||
  333. (!self._origOrder.length && self._$targets.length)
  334. ){
  335. self._origOrder = [];
  336. for(var i = 0; i < self._$targets.length; i++){
  337. var target = self._$targets[i];
  338. self._origOrder.push(target);
  339. }
  340. }
  341. self._execAction('_refresh', 1, arguments);
  342. },
  343. /**
  344. * Bind Handlers
  345. * @since 2.0.0
  346. */
  347. _bindHandlers: function(){
  348. var self = this,
  349. filters = $.MixItUp.prototype._bound._filter,
  350. sorts = $.MixItUp.prototype._bound._sort;
  351. self._execAction('_bindHandlers', 0);
  352. if(self.controls.live){
  353. self._$body
  354. .on('click.mixItUp.'+self._id, self.selectors.sort, function(){
  355. self._processClick($(this), 'sort');
  356. })
  357. .on('click.mixItUp.'+self._id, self.selectors.filter, function(){
  358. self._processClick($(this), 'filter');
  359. });
  360. } else {
  361. self._$sortButtons = $(self.selectors.sort);
  362. self._$filterButtons = $(self.selectors.filter);
  363. self._$sortButtons.on('click.mixItUp.'+self._id, function(){
  364. self._processClick($(this), 'sort');
  365. });
  366. self._$filterButtons.on('click.mixItUp.'+self._id, function(){
  367. self._processClick($(this), 'filter');
  368. });
  369. }
  370. filters[self.selectors.filter] = (filters[self.selectors.filter] === undf) ? 1 : filters[self.selectors.filter] + 1;
  371. sorts[self.selectors.sort] = (sorts[self.selectors.sort] === undf) ? 1 : sorts[self.selectors.sort] + 1;
  372. self._execAction('_bindHandlers', 1);
  373. },
  374. /**
  375. * Process Click
  376. * @since 2.0.0
  377. * @param {object} $button
  378. * @param {string} type
  379. */
  380. _processClick: function($button, type){
  381. var self = this,
  382. trackClick = function($button, type, off){
  383. var proto = $.MixItUp.prototype;
  384. proto._handled['_'+type][self.selectors[type]] = (proto._handled['_'+type][self.selectors[type]] === undf) ?
  385. 1 :
  386. proto._handled['_'+type][self.selectors[type]] + 1;
  387. if(proto._handled['_'+type][self.selectors[type]] === proto._bound['_'+type][self.selectors[type]]){
  388. $button[(off ? 'remove' : 'add')+'Class'](self.controls.activeClass);
  389. delete proto._handled['_'+type][self.selectors[type]];
  390. }
  391. };
  392. self._execAction('_processClick', 0, arguments);
  393. if(!self._mixing || (self.animation.queue && self._queue.length < self.animation.queueLimit)){
  394. self._clicking = true;
  395. if(type === 'sort'){
  396. var sort = $button.attr('data-sort');
  397. if(!$button.hasClass(self.controls.activeClass) || sort.indexOf('random') > -1){
  398. $(self.selectors.sort).removeClass(self.controls.activeClass);
  399. trackClick($button, type);
  400. self.sort(sort);
  401. }
  402. }
  403. if(type === 'filter') {
  404. var filter = $button.attr('data-filter'),
  405. ndx,
  406. seperator = self.controls.toggleLogic === 'or' ? ',' : '';
  407. if(!self.controls.toggleFilterButtons){
  408. if(!$button.hasClass(self.controls.activeClass)){
  409. $(self.selectors.filter).removeClass(self.controls.activeClass);
  410. trackClick($button, type);
  411. self.filter(filter);
  412. }
  413. } else {
  414. self._buildToggleArray();
  415. if(!$button.hasClass(self.controls.activeClass)){
  416. trackClick($button, type);
  417. self._toggleArray.push(filter);
  418. } else {
  419. trackClick($button, type, true);
  420. ndx = self._toggleArray.indexOf(filter);
  421. self._toggleArray.splice(ndx, 1);
  422. }
  423. self._toggleArray = $.grep(self._toggleArray,function(n){return(n);});
  424. self._toggleString = self._toggleArray.join(seperator);
  425. self.filter(self._toggleString);
  426. }
  427. }
  428. self._execAction('_processClick', 1, arguments);
  429. } else {
  430. if(typeof self.callbacks.onMixBusy === 'function'){
  431. self.callbacks.onMixBusy.call(self._domNode, self._state, self);
  432. }
  433. self._execAction('_processClickBusy', 1, arguments);
  434. }
  435. },
  436. /**
  437. * Build Toggle Array
  438. * @since 2.0.0
  439. */
  440. _buildToggleArray: function(){
  441. var self = this,
  442. activeFilter = self._activeFilter.replace(/\s/g, '');
  443. self._execAction('_buildToggleArray', 0, arguments);
  444. if(self.controls.toggleLogic === 'or'){
  445. self._toggleArray = activeFilter.split(',');
  446. } else {
  447. self._toggleArray = activeFilter.split('.');
  448. !self._toggleArray[0] && self._toggleArray.shift();
  449. for(var i = 0, filter; filter = self._toggleArray[i]; i++){
  450. self._toggleArray[i] = '.'+filter;
  451. }
  452. }
  453. self._execAction('_buildToggleArray', 1, arguments);
  454. },
  455. /**
  456. * Update Controls
  457. * @since 2.0.0
  458. * @param {object} command
  459. * @param {boolean} multi
  460. */
  461. _updateControls: function(command, multi){
  462. var self = this,
  463. output = {
  464. filter: command.filter,
  465. sort: command.sort
  466. },
  467. update = function($el, filter){
  468. try {
  469. (multi && type === 'filter' && !(output.filter === 'none' || output.filter === '')) ?
  470. $el.filter(filter).addClass(self.controls.activeClass) :
  471. $el.removeClass(self.controls.activeClass).filter(filter).addClass(self.controls.activeClass);
  472. } catch(e) {}
  473. },
  474. type = 'filter',
  475. $el = null;
  476. self._execAction('_updateControls', 0, arguments);
  477. (command.filter === undf) && (output.filter = self._activeFilter);
  478. (command.sort === undf) && (output.sort = self._activeSort);
  479. (output.filter === self.selectors.target) && (output.filter = 'all');
  480. for(var i = 0; i < 2; i++){
  481. $el = self.controls.live ? $(self.selectors[type]) : self['_$'+type+'Buttons'];
  482. $el && update($el, '[data-'+type+'="'+output[type]+'"]');
  483. type = 'sort';
  484. }
  485. self._execAction('_updateControls', 1, arguments);
  486. },
  487. /**
  488. * Filter (private)
  489. * @since 2.0.0
  490. */
  491. _filter: function(){
  492. var self = this;
  493. self._execAction('_filter', 0);
  494. for(var i = 0; i < self._$targets.length; i++){
  495. var $target = $(self._$targets[i]);
  496. if($target.is(self._activeFilter)){
  497. self._$show = self._$show.add($target);
  498. } else {
  499. self._$hide = self._$hide.add($target);
  500. }
  501. }
  502. self._execAction('_filter', 1);
  503. },
  504. /**
  505. * Sort (private)
  506. * @since 2.0.0
  507. */
  508. _sort: function(){
  509. var self = this,
  510. arrayShuffle = function(oldArray){
  511. var newArray = oldArray.slice(),
  512. len = newArray.length,
  513. i = len;
  514. while(i--){
  515. var p = parseInt(Math.random()*len);
  516. var t = newArray[i];
  517. newArray[i] = newArray[p];
  518. newArray[p] = t;
  519. };
  520. return newArray;
  521. };
  522. self._execAction('_sort', 0);
  523. self._startOrder = [];
  524. for(var i = 0; i < self._$targets.length; i++){
  525. var target = self._$targets[i];
  526. self._startOrder.push(target);
  527. }
  528. switch(self._newSort[0].sortBy){
  529. case 'default':
  530. self._newOrder = self._origOrder;
  531. break;
  532. case 'random':
  533. self._newOrder = arrayShuffle(self._startOrder);
  534. break;
  535. case 'custom':
  536. self._newOrder = self._newSort[0].order;
  537. break;
  538. default:
  539. self._newOrder = self._startOrder.concat().sort(function(a, b){
  540. return self._compare(a, b);
  541. });
  542. }
  543. self._execAction('_sort', 1);
  544. },
  545. /**
  546. * Compare Algorithm
  547. * @since 2.0.0
  548. * @param {string|number} a
  549. * @param {string|number} b
  550. * @param {number} depth (recursion)
  551. * @return {number}
  552. */
  553. _compare: function(a, b, depth){
  554. depth = depth ? depth : 0;
  555. var self = this,
  556. order = self._newSort[depth].order,
  557. getData = function(el){
  558. return el.dataset[self._newSort[depth].sortBy] || 0;
  559. },
  560. attrA = isNaN(getData(a) * 1) ? getData(a).toLowerCase() : getData(a) * 1,
  561. attrB = isNaN(getData(b) * 1) ? getData(b).toLowerCase() : getData(b) * 1;
  562. if(attrA < attrB)
  563. return order === 'asc' ? -1 : 1;
  564. if(attrA > attrB)
  565. return order === 'asc' ? 1 : -1;
  566. if(attrA === attrB && self._newSort.length > depth+1)
  567. return self._compare(a, b, depth+1);
  568. return 0;
  569. },
  570. /**
  571. * Print Sort
  572. * @since 2.0.0
  573. * @param {boolean} reset
  574. */
  575. _printSort: function(reset){
  576. var self = this,
  577. order = reset ? self._startOrder : self._newOrder,
  578. targets = self._$parent[0].querySelectorAll(self.selectors.target),
  579. nextSibling = targets.length ? targets[targets.length -1].nextElementSibling : null,
  580. frag = document.createDocumentFragment();
  581. self._execAction('_printSort', 0, arguments);
  582. for(var i = 0; i < targets.length; i++){
  583. var target = targets[i],
  584. whiteSpace = target.nextSibling;
  585. if(target.style.position === 'absolute') continue;
  586. if(whiteSpace && whiteSpace.nodeName === '#text'){
  587. self._$parent[0].removeChild(whiteSpace);
  588. }
  589. self._$parent[0].removeChild(target);
  590. }
  591. for(var i = 0; i < order.length; i++){
  592. var el = order[i];
  593. if(self._newSort[0].sortBy === 'default' && self._newSort[0].order === 'desc' && !reset){
  594. var firstChild = frag.firstChild;
  595. frag.insertBefore(el, firstChild);
  596. frag.insertBefore(document.createTextNode(' '), el);
  597. } else {
  598. frag.appendChild(el);
  599. frag.appendChild(document.createTextNode(' '));
  600. }
  601. }
  602. nextSibling ?
  603. self._$parent[0].insertBefore(frag, nextSibling) :
  604. self._$parent[0].appendChild(frag);
  605. self._execAction('_printSort', 1, arguments);
  606. },
  607. /**
  608. * Parse Sort
  609. * @since 2.0.0
  610. * @param {string} sortString
  611. * @return {array} newSort
  612. */
  613. _parseSort: function(sortString){
  614. var self = this,
  615. rules = typeof sortString === 'string' ? sortString.split(' ') : [sortString],
  616. newSort = [];
  617. for(var i = 0; i < rules.length; i++){
  618. var rule = typeof sortString === 'string' ? rules[i].split(':') : ['custom', rules[i]],
  619. ruleObj = {
  620. sortBy: self._helpers._camelCase(rule[0]),
  621. order: rule[1] || 'asc'
  622. };
  623. newSort.push(ruleObj);
  624. if(ruleObj.sortBy === 'default' || ruleObj.sortBy === 'random') break;
  625. }
  626. return self._execFilter('_parseSort', newSort, arguments);
  627. },
  628. /**
  629. * Parse Effects
  630. * @since 2.0.0
  631. * @return {object} effects
  632. */
  633. _parseEffects: function(){
  634. var self = this,
  635. effects = {
  636. opacity: '',
  637. transformIn: '',
  638. transformOut: '',
  639. filter: ''
  640. },
  641. parse = function(effect, extract, reverse){
  642. if(self.animation.effects.indexOf(effect) > -1){
  643. if(extract){
  644. var propIndex = self.animation.effects.indexOf(effect+'(');
  645. if(propIndex > -1){
  646. var str = self.animation.effects.substring(propIndex),
  647. match = /\(([^)]+)\)/.exec(str),
  648. val = match[1];
  649. return {val: val};
  650. }
  651. }
  652. return true;
  653. } else {
  654. return false;
  655. }
  656. },
  657. negate = function(value, invert){
  658. if(invert){
  659. return value.charAt(0) === '-' ? value.substr(1, value.length) : '-'+value;
  660. } else {
  661. return value;
  662. }
  663. },
  664. buildTransform = function(key, invert){
  665. var transforms = [
  666. ['scale', '.01'],
  667. ['translateX', '20px'],
  668. ['translateY', '20px'],
  669. ['translateZ', '20px'],
  670. ['rotateX', '90deg'],
  671. ['rotateY', '90deg'],
  672. ['rotateZ', '180deg'],
  673. ];
  674. for(var i = 0; i < transforms.length; i++){
  675. var prop = transforms[i][0],
  676. def = transforms[i][1],
  677. inverted = invert && prop !== 'scale';
  678. effects[key] += parse(prop) ? prop+'('+negate(parse(prop, true).val || def, inverted)+') ' : '';
  679. }
  680. };
  681. effects.opacity = parse('fade') ? parse('fade',true).val || '0' : '1';
  682. buildTransform('transformIn');
  683. self.animation.reverseOut ? buildTransform('transformOut', true) : (effects.transformOut = effects.transformIn);
  684. effects.transition = {};
  685. effects.transition = self._getPrefixedCSS('transition','all '+self.animation.duration+'ms '+self.animation.easing+', opacity '+self.animation.duration+'ms linear');
  686. self.animation.stagger = parse('stagger') ? true : false;
  687. self.animation.staggerDuration = parseInt(parse('stagger') ? (parse('stagger',true).val ? parse('stagger',true).val : 100) : 100);
  688. return self._execFilter('_parseEffects', effects);
  689. },
  690. /**
  691. * Build State
  692. * @since 2.0.0
  693. * @param {boolean} future
  694. * @return {object} futureState
  695. */
  696. _buildState: function(future){
  697. var self = this,
  698. state = {};
  699. self._execAction('_buildState', 0);
  700. state = {
  701. activeFilter: self._activeFilter === '' ? 'none' : self._activeFilter,
  702. activeSort: future && self._newSortString ? self._newSortString : self._activeSort,
  703. fail: !self._$show.length && self._activeFilter !== '',
  704. $targets: self._$targets,
  705. $show: self._$show,
  706. $hide: self._$hide,
  707. totalTargets: self._$targets.length,
  708. totalShow: self._$show.length,
  709. totalHide: self._$hide.length,
  710. display: future && self._newDisplay ? self._newDisplay : self.layout.display
  711. };
  712. if(future){
  713. return self._execFilter('_buildState', state);
  714. } else {
  715. self._state = state;
  716. self._execAction('_buildState', 1);
  717. }
  718. },
  719. /**
  720. * Go Mix
  721. * @since 2.0.0
  722. * @param {boolean} animate
  723. */
  724. _goMix: function(animate){
  725. var self = this,
  726. phase1 = function(){
  727. if(self._chrome && (self._chrome === 31)){
  728. chromeFix(self._$parent[0]);
  729. }
  730. self._setInter();
  731. phase2();
  732. },
  733. phase2 = function(){
  734. var scrollTop = window.pageYOffset,
  735. scrollLeft = window.pageXOffset,
  736. docHeight = document.documentElement.scrollHeight;
  737. self._getInterMixData();
  738. self._setFinal();
  739. self._getFinalMixData();
  740. (window.pageYOffset !== scrollTop) && window.scrollTo(scrollLeft, scrollTop);
  741. self._prepTargets();
  742. if(window.requestAnimationFrame){
  743. requestAnimationFrame(phase3);
  744. } else {
  745. setTimeout(function(){
  746. phase3();
  747. },20);
  748. }
  749. },
  750. phase3 = function(){
  751. self._animateTargets();
  752. if(self._targetsBound === 0){
  753. self._cleanUp();
  754. }
  755. },
  756. chromeFix = function(grid){
  757. var parent = grid.parentElement,
  758. placeholder = document.createElement('div'),
  759. frag = document.createDocumentFragment();
  760. parent.insertBefore(placeholder, grid);
  761. frag.appendChild(grid);
  762. parent.replaceChild(grid, placeholder);
  763. },
  764. futureState = self._buildState(true);
  765. self._execAction('_goMix', 0, arguments);
  766. !self.animation.duration && (animate = false);
  767. self._mixing = true;
  768. self._$container.removeClass(self.layout.containerClassFail);
  769. if(typeof self.callbacks.onMixStart === 'function'){
  770. self.callbacks.onMixStart.call(self._domNode, self._state, futureState, self);
  771. }
  772. self._$container.trigger('mixStart', [self._state, futureState, self]);
  773. self._getOrigMixData();
  774. if(animate && !self._suckMode){
  775. window.requestAnimationFrame ?
  776. requestAnimationFrame(phase1) :
  777. phase1();
  778. } else {
  779. self._cleanUp();
  780. }
  781. self._execAction('_goMix', 1, arguments);
  782. },
  783. /**
  784. * Get Target Data
  785. * @since 2.0.0
  786. */
  787. _getTargetData: function(el, stage){
  788. var self = this,
  789. elStyle;
  790. el.dataset[stage+'PosX'] = el.offsetLeft;
  791. el.dataset[stage+'PosY'] = el.offsetTop;
  792. if(self.animation.animateResizeTargets){
  793. elStyle = !self._suckMode ?
  794. window.getComputedStyle(el) :
  795. {
  796. marginBottom: '',
  797. marginRight: ''
  798. };
  799. el.dataset[stage+'MarginBottom'] = parseInt(elStyle.marginBottom);
  800. el.dataset[stage+'MarginRight'] = parseInt(elStyle.marginRight);
  801. el.dataset[stage+'Width'] = el.offsetWidth;
  802. el.dataset[stage+'Height'] = el.offsetHeight;
  803. }
  804. },
  805. /**
  806. * Get Original Mix Data
  807. * @since 2.0.0
  808. */
  809. _getOrigMixData: function(){
  810. var self = this,
  811. parentStyle = !self._suckMode ? window.getComputedStyle(self._$parent[0]) : {boxSizing: ''},
  812. parentBS = parentStyle.boxSizing || parentStyle[self._vendor+'BoxSizing'];
  813. self._incPadding = (parentBS === 'border-box');
  814. self._execAction('_getOrigMixData', 0);
  815. !self._suckMode && (self.effects = self._parseEffects());
  816. self._$toHide = self._$hide.filter(':visible');
  817. self._$toShow = self._$show.filter(':hidden');
  818. self._$pre = self._$targets.filter(':visible');
  819. self._startHeight = self._incPadding ?
  820. self._$parent.outerHeight() :
  821. self._$parent.height();
  822. for(var i = 0; i < self._$pre.length; i++){
  823. var el = self._$pre[i];
  824. self._getTargetData(el, 'orig');
  825. }
  826. self._execAction('_getOrigMixData', 1);
  827. },
  828. /**
  829. * Set Intermediate Positions
  830. * @since 2.0.0
  831. */
  832. _setInter: function(){
  833. var self = this;
  834. self._execAction('_setInter', 0);
  835. if(self._changingLayout && self.animation.animateChangeLayout){
  836. self._$toShow.css('display',self._newDisplay);
  837. if(self._changingClass){
  838. self._$container
  839. .removeClass(self.layout.containerClass)
  840. .addClass(self._newClass);
  841. }
  842. } else {
  843. self._$toShow.css('display', self.layout.display);
  844. }
  845. self._execAction('_setInter', 1);
  846. },
  847. /**
  848. * Get Intermediate Mix Data
  849. * @since 2.0.0
  850. */
  851. _getInterMixData: function(){
  852. var self = this;
  853. self._execAction('_getInterMixData', 0);
  854. for(var i = 0; i < self._$toShow.length; i++){
  855. var el = self._$toShow[i];
  856. self._getTargetData(el, 'inter');
  857. }
  858. for(var i = 0; i < self._$pre.length; i++){
  859. var el = self._$pre[i];
  860. self._getTargetData(el, 'inter');
  861. }
  862. self._execAction('_getInterMixData', 1);
  863. },
  864. /**
  865. * Set Final Positions
  866. * @since 2.0.0
  867. */
  868. _setFinal: function(){
  869. var self = this;
  870. self._execAction('_setFinal', 0);
  871. self._sorting && self._printSort();
  872. self._$toHide.removeStyle('display');
  873. if(self._changingLayout && self.animation.animateChangeLayout){
  874. self._$pre.css('display',self._newDisplay);
  875. }
  876. self._execAction('_setFinal', 1);
  877. },
  878. /**
  879. * Get Final Mix Data
  880. * @since 2.0.0
  881. */
  882. _getFinalMixData: function(){
  883. var self = this;
  884. self._execAction('_getFinalMixData', 0);
  885. for(var i = 0; i < self._$toShow.length; i++){
  886. var el = self._$toShow[i];
  887. self._getTargetData(el, 'final');
  888. }
  889. for(var i = 0; i < self._$pre.length; i++){
  890. var el = self._$pre[i];
  891. self._getTargetData(el, 'final');
  892. }
  893. self._newHeight = self._incPadding ?
  894. self._$parent.outerHeight() :
  895. self._$parent.height();
  896. self._sorting && self._printSort(true);
  897. self._$toShow.removeStyle('display');
  898. self._$pre.css('display',self.layout.display);
  899. if(self._changingClass && self.animation.animateChangeLayout){
  900. self._$container
  901. .removeClass(self._newClass)
  902. .addClass(self.layout.containerClass);
  903. }
  904. self._execAction('_getFinalMixData', 1);
  905. },
  906. /**
  907. * Prepare Targets
  908. * @since 2.0.0
  909. */
  910. _prepTargets: function(){
  911. var self = this,
  912. transformCSS = {
  913. _in: self._getPrefixedCSS('transform', self.effects.transformIn),
  914. _out: self._getPrefixedCSS('transform', self.effects.transformOut)
  915. };
  916. self._execAction('_prepTargets', 0);
  917. if(self.animation.animateResizeContainer){
  918. self._$parent.css('height',self._startHeight+'px');
  919. }
  920. for(var i = 0; i < self._$toShow.length; i++){
  921. var el = self._$toShow[i],
  922. $el = $(el);
  923. el.style.opacity = self.effects.opacity;
  924. el.style.display = (self._changingLayout && self.animation.animateChangeLayout) ?
  925. self._newDisplay :
  926. self.layout.display;
  927. $el.css(transformCSS._in);
  928. if(self.animation.animateResizeTargets){
  929. el.style.width = el.dataset.finalWidth+'px';
  930. el.style.height = el.dataset.finalHeight+'px';
  931. el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth) + (el.dataset.finalMarginRight * 1)+'px';
  932. el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight) + (el.dataset.finalMarginBottom * 1)+'px';
  933. }
  934. }
  935. for(var i = 0; i < self._$pre.length; i++){
  936. var el = self._$pre[i],
  937. $el = $(el),
  938. translate = {
  939. x: el.dataset.origPosX - el.dataset.interPosX,
  940. y: el.dataset.origPosY - el.dataset.interPosY
  941. },
  942. transformCSS = self._getPrefixedCSS('transform','translate('+translate.x+'px,'+translate.y+'px)');
  943. $el.css(transformCSS);
  944. if(self.animation.animateResizeTargets){
  945. el.style.width = el.dataset.origWidth+'px';
  946. el.style.height = el.dataset.origHeight+'px';
  947. if(el.dataset.origWidth - el.dataset.finalWidth){
  948. el.style.marginRight = -(el.dataset.origWidth - el.dataset.interWidth) + (el.dataset.origMarginRight * 1)+'px';
  949. }
  950. if(el.dataset.origHeight - el.dataset.finalHeight){
  951. el.style.marginBottom = -(el.dataset.origHeight - el.dataset.interHeight) + (el.dataset.origMarginBottom * 1) +'px';
  952. }
  953. }
  954. }
  955. self._execAction('_prepTargets', 1);
  956. },
  957. /**
  958. * Animate Targets
  959. * @since 2.0.0
  960. */
  961. _animateTargets: function(){
  962. var self = this;
  963. self._execAction('_animateTargets', 0);
  964. self._targetsDone = 0;
  965. self._targetsBound = 0;
  966. self._$parent
  967. .css(self._getPrefixedCSS('perspective', self.animation.perspectiveDistance+'px'))
  968. .css(self._getPrefixedCSS('perspective-origin', self.animation.perspectiveOrigin));
  969. if(self.animation.animateResizeContainer){
  970. self._$parent
  971. .css(self._getPrefixedCSS('transition','height '+self.animation.duration+'ms ease'))
  972. .css('height',self._newHeight+'px');
  973. }
  974. for(var i = 0; i < self._$toShow.length; i++){
  975. var el = self._$toShow[i],
  976. $el = $(el),
  977. translate = {
  978. x: el.dataset.finalPosX - el.dataset.interPosX,
  979. y: el.dataset.finalPosY - el.dataset.interPosY
  980. },
  981. delay = self._getDelay(i),
  982. toShowCSS = {};
  983. el.style.opacity = '';
  984. for(var j = 0; j < 2; j++){
  985. var a = j === 0 ? a = self._prefix : '';
  986. if(self._ff && self._ff <= 20){
  987. toShowCSS[a+'transition-property'] = 'all';
  988. toShowCSS[a+'transition-timing-function'] = self.animation.easing+'ms';
  989. toShowCSS[a+'transition-duration'] = self.animation.duration+'ms';
  990. }
  991. toShowCSS[a+'transition-delay'] = delay+'ms';
  992. toShowCSS[a+'transform'] = 'translate('+translate.x+'px,'+translate.y+'px)';
  993. }
  994. if(self.effects.transform || self.effects.opacity){
  995. self._bindTargetDone($el);
  996. }
  997. (self._ff && self._ff <= 20) ?
  998. $el.css(toShowCSS) :
  999. $el.css(self.effects.transition).css(toShowCSS);
  1000. }
  1001. for(var i = 0; i < self._$pre.length; i++){
  1002. var el = self._$pre[i],
  1003. $el = $(el),
  1004. translate = {
  1005. x: el.dataset.finalPosX - el.dataset.interPosX,
  1006. y: el.dataset.finalPosY - el.dataset.interPosY
  1007. },
  1008. delay = self._getDelay(i);
  1009. if(!(
  1010. el.dataset.finalPosX === el.dataset.origPosX &&
  1011. el.dataset.finalPosY === el.dataset.origPosY
  1012. )){
  1013. self._bindTargetDone($el);
  1014. }
  1015. $el.css(self._getPrefixedCSS('transition', 'all '+self.animation.duration+'ms '+self.animation.easing+' '+delay+'ms'));
  1016. $el.css(self._getPrefixedCSS('transform', 'translate('+translate.x+'px,'+translate.y+'px)'));
  1017. if(self.animation.animateResizeTargets){
  1018. if(el.dataset.origWidth - el.dataset.finalWidth && el.dataset.finalWidth * 1){
  1019. el.style.width = el.dataset.finalWidth+'px';
  1020. el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth)+(el.dataset.finalMarginRight * 1)+'px';
  1021. }
  1022. if(el.dataset.origHeight - el.dataset.finalHeight && el.dataset.finalHeight * 1){
  1023. el.style.height = el.dataset.finalHeight+'px';
  1024. el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight)+(el.dataset.finalMarginBottom * 1) +'px';
  1025. }
  1026. }
  1027. }
  1028. if(self._changingClass){
  1029. self._$container
  1030. .removeClass(self.layout.containerClass)
  1031. .addClass(self._newClass);
  1032. }
  1033. for(var i = 0; i < self._$toHide.length; i++){
  1034. var el = self._$toHide[i],
  1035. $el = $(el),
  1036. delay = self._getDelay(i),
  1037. toHideCSS = {};
  1038. for(var j = 0; j<2; j++){
  1039. var a = j === 0 ? a = self._prefix : '';
  1040. toHideCSS[a+'transition-delay'] = delay+'ms';
  1041. toHideCSS[a+'transform'] = self.effects.transformOut;
  1042. toHideCSS.opacity = self.effects.opacity;
  1043. }
  1044. $el.css(self.effects.transition).css(toHideCSS);
  1045. if(self.effects.transform || self.effects.opacity){
  1046. self._bindTargetDone($el);
  1047. };
  1048. }
  1049. self._execAction('_animateTargets', 1);
  1050. },
  1051. /**
  1052. * Bind Targets TransitionEnd
  1053. * @since 2.0.0
  1054. * @param {object} $el
  1055. */
  1056. _bindTargetDone: function($el){
  1057. var self = this,
  1058. el = $el[0];
  1059. self._execAction('_bindTargetDone', 0, arguments);
  1060. if(!el.dataset.bound){
  1061. el.dataset.bound = true;
  1062. self._targetsBound++;
  1063. $el.on('webkitTransitionEnd.mixItUp transitionend.mixItUp',function(e){
  1064. if(
  1065. (e.originalEvent.propertyName.indexOf('transform') > -1 ||
  1066. e.originalEvent.propertyName.indexOf('opacity') > -1) &&
  1067. $(e.originalEvent.target).is(self.selectors.target)
  1068. ){
  1069. $el.off('.mixItUp');
  1070. delete el.dataset.bound;
  1071. self._targetDone();
  1072. }
  1073. });
  1074. }
  1075. self._execAction('_bindTargetDone', 1, arguments);
  1076. },
  1077. /**
  1078. * Target Done
  1079. * @since 2.0.0
  1080. */
  1081. _targetDone: function(){
  1082. var self = this;
  1083. self._execAction('_targetDone', 0);
  1084. self._targetsDone++;
  1085. (self._targetsDone === self._targetsBound) && self._cleanUp();
  1086. self._execAction('_targetDone', 1);
  1087. },
  1088. /**
  1089. * Clean Up
  1090. * @since 2.0.0
  1091. */
  1092. _cleanUp: function(){
  1093. var self = this,
  1094. targetStyles = self.animation.animateResizeTargets ?
  1095. 'transform opacity width height margin-bottom margin-right' :
  1096. 'transform opacity',
  1097. unBrake = function(){
  1098. self._$targets.removeStyle('transition', self._prefix);
  1099. };
  1100. self._execAction('_cleanUp', 0);
  1101. !self._changingLayout ?
  1102. self._$show.css('display',self.layout.display) :
  1103. self._$show.css('display',self._newDisplay);
  1104. self._$targets.css(self._brake);
  1105. self._$targets
  1106. .removeStyle(targetStyles, self._prefix)
  1107. .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');
  1108. self._$hide.removeStyle('display');
  1109. self._$parent.removeStyle('height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin', self._prefix);
  1110. if(self._sorting){
  1111. self._printSort();
  1112. self._activeSort = self._newSortString;
  1113. self._sorting = false;
  1114. }
  1115. if(self._changingLayout){
  1116. if(self._changingDisplay){
  1117. self.layout.display = self._newDisplay;
  1118. self._changingDisplay = false;
  1119. }
  1120. if(self._changingClass){
  1121. self._$parent.removeClass(self.layout.containerClass).addClass(self._newClass);
  1122. self.layout.containerClass = self._newClass;
  1123. self._changingClass = false;
  1124. }
  1125. self._changingLayout = false;
  1126. }
  1127. self._refresh();
  1128. self._buildState();
  1129. if(self._state.fail){
  1130. self._$container.addClass(self.layout.containerClassFail);
  1131. }
  1132. self._$show = $();
  1133. self._$hide = $();
  1134. if(window.requestAnimationFrame){
  1135. requestAnimationFrame(unBrake);
  1136. }
  1137. self._mixing = false;
  1138. if(typeof self.callbacks._user === 'function'){
  1139. self.callbacks._user.call(self._domNode, self._state, self);
  1140. }
  1141. if(typeof self.callbacks.onMixEnd === 'function'){
  1142. self.callbacks.onMixEnd.call(self._domNode, self._state, self);
  1143. }
  1144. self._$container.trigger('mixEnd', [self._state, self]);
  1145. if(self._state.fail){
  1146. (typeof self.callbacks.onMixFail === 'function') && self.callbacks.onMixFail.call(self._domNode, self._state, self);
  1147. self._$container.trigger('mixFail', [self._state, self]);
  1148. }
  1149. if(self._loading){
  1150. (typeof self.callbacks.onMixLoad === 'function') && self.callbacks.onMixLoad.call(self._domNode, self._state, self);
  1151. self._$container.trigger('mixLoad', [self._state, self]);
  1152. }
  1153. if(self._queue.length){
  1154. self._execAction('_queue', 0);
  1155. self.multiMix(self._queue[0][0],self._queue[0][1],self._queue[0][2]);
  1156. self._queue.splice(0, 1);
  1157. }
  1158. self._execAction('_cleanUp', 1);
  1159. self._loading = false;
  1160. },
  1161. /**
  1162. * Get Prefixed CSS
  1163. * @since 2.0.0
  1164. * @param {string} property
  1165. * @param {string} value
  1166. * @param {boolean} prefixValue
  1167. * @return {object} styles
  1168. */
  1169. _getPrefixedCSS: function(property, value, prefixValue){
  1170. var self = this,
  1171. styles = {},
  1172. prefix = '',
  1173. i = -1;
  1174. for(i = 0; i < 2; i++){
  1175. prefix = i === 0 ? self._prefix : '';
  1176. prefixValue ? styles[prefix+property] = prefix+value : styles[prefix+property] = value;
  1177. }
  1178. return self._execFilter('_getPrefixedCSS', styles, arguments);
  1179. },
  1180. /**
  1181. * Get Delay
  1182. * @since 2.0.0
  1183. * @param {number} i
  1184. * @return {number} delay
  1185. */
  1186. _getDelay: function(i){
  1187. var self = this,
  1188. n = typeof self.animation.staggerSequence === 'function' ? self.animation.staggerSequence.call(self._domNode, i, self._state) : i,
  1189. delay = self.animation.stagger ? n * self.animation.staggerDuration : 0;
  1190. return self._execFilter('_getDelay', delay, arguments);
  1191. },
  1192. /**
  1193. * Parse MultiMix Arguments
  1194. * @since 2.0.0
  1195. * @param {array} args
  1196. * @return {object} output
  1197. */
  1198. _parseMultiMixArgs: function(args){
  1199. var self = this,
  1200. output = {
  1201. command: null,
  1202. animate: self.animation.enable,
  1203. callback: null
  1204. };
  1205. for(var i = 0; i < args.length; i++){
  1206. var arg = args[i];
  1207. if(arg !== null){
  1208. if(typeof arg === 'object' || typeof arg === 'string'){
  1209. output.command = arg;
  1210. } else if(typeof arg === 'boolean'){
  1211. output.animate = arg;
  1212. } else if(typeof arg === 'function'){
  1213. output.callback = arg;
  1214. }
  1215. }
  1216. }
  1217. return self._execFilter('_parseMultiMixArgs', output, arguments);
  1218. },
  1219. /**
  1220. * Parse Insert Arguments
  1221. * @since 2.0.0
  1222. * @param {array} args
  1223. * @return {object} output
  1224. */
  1225. _parseInsertArgs: function(args){
  1226. var self = this,
  1227. output = {
  1228. index: 0,
  1229. $object: $(),
  1230. multiMix: {filter: self._state.activeFilter},
  1231. callback: null
  1232. };
  1233. for(var i = 0; i < args.length; i++){
  1234. var arg = args[i];
  1235. if(typeof arg === 'number'){
  1236. output.index = arg;
  1237. } else if(typeof arg === 'object' && arg instanceof $){
  1238. output.$object = arg;
  1239. } else if(typeof arg === 'object' && self._helpers._isElement(arg)){
  1240. output.$object = $(arg);
  1241. } else if(typeof arg === 'object' && arg !== null){
  1242. output.multiMix = arg;
  1243. } else if(typeof arg === 'boolean' && !arg){
  1244. output.multiMix = false;
  1245. } else if(typeof arg === 'function'){
  1246. output.callback = arg;
  1247. }
  1248. }
  1249. return self._execFilter('_parseInsertArgs', output, arguments);
  1250. },
  1251. /**
  1252. * Execute Action
  1253. * @since 2.0.0
  1254. * @param {string} methodName
  1255. * @param {boolean} isPost
  1256. * @param {array} args
  1257. */
  1258. _execAction: function(methodName, isPost, args){
  1259. var self = this,
  1260. context = isPost ? 'post' : 'pre';
  1261. if(!self._actions.isEmptyObject && self._actions.hasOwnProperty(methodName)){
  1262. for(var key in self._actions[methodName][context]){
  1263. self._actions[methodName][context][key].call(self, args);
  1264. }
  1265. }
  1266. },
  1267. /**
  1268. * Execute Filter
  1269. * @since 2.0.0
  1270. * @param {string} methodName
  1271. * @param {mixed} value
  1272. * @return {mixed} value
  1273. */
  1274. _execFilter: function(methodName, value, args){
  1275. var self = this;
  1276. if(!self._filters.isEmptyObject && self._filters.hasOwnProperty(methodName)){
  1277. for(var key in self._filters[methodName]){
  1278. return self._filters[methodName][key].call(self, args);
  1279. }
  1280. } else {
  1281. return value;
  1282. }
  1283. },
  1284. /* Helpers
  1285. ---------------------------------------------------------------------- */
  1286. _helpers: {
  1287. /**
  1288. * CamelCase
  1289. * @since 2.0.0
  1290. * @param {string}
  1291. * @return {string}
  1292. */
  1293. _camelCase: function(string){
  1294. return string.replace(/-([a-z])/g, function(g){
  1295. return g[1].toUpperCase();
  1296. });
  1297. },
  1298. /**
  1299. * Is Element
  1300. * @since 2.1.3
  1301. * @param {object} element to test
  1302. * @return {boolean}
  1303. */
  1304. _isElement: function(el){
  1305. if(window.HTMLElement){
  1306. return el instanceof HTMLElement;
  1307. } else {
  1308. return (
  1309. el !== null &&
  1310. el.nodeType === 1 &&
  1311. el.nodeName === 'string'
  1312. );
  1313. }
  1314. }
  1315. },
  1316. /* Public Methods
  1317. ---------------------------------------------------------------------- */
  1318. /**
  1319. * Is Mixing
  1320. * @since 2.0.0
  1321. * @return {boolean}
  1322. */
  1323. isMixing: function(){
  1324. var self = this;
  1325. return self._execFilter('isMixing', self._mixing);
  1326. },
  1327. /**
  1328. * Filter (public)
  1329. * @since 2.0.0
  1330. * @param {array} arguments
  1331. */
  1332. filter: function(){
  1333. var self = this,
  1334. args = self._parseMultiMixArgs(arguments);
  1335. self._clicking && (self._toggleString = '');
  1336. self.multiMix({filter: args.command}, args.animate, args.callback);
  1337. },
  1338. /**
  1339. * Sort (public)
  1340. * @since 2.0.0
  1341. * @param {array} arguments
  1342. */
  1343. sort: function(){
  1344. var self = this,
  1345. args = self._parseMultiMixArgs(arguments);
  1346. self.multiMix({sort: args.command}, args.animate, args.callback);
  1347. },
  1348. /**
  1349. * Change Layout (public)
  1350. * @since 2.0.0
  1351. * @param {array} arguments
  1352. */
  1353. changeLayout: function(){
  1354. var self = this,
  1355. args = self._parseMultiMixArgs(arguments);
  1356. self.multiMix({changeLayout: args.command}, args.animate, args.callback);
  1357. },
  1358. /**
  1359. * MultiMix
  1360. * @since 2.0.0
  1361. * @param {array} arguments
  1362. */
  1363. multiMix: function(){
  1364. var self = this,
  1365. args = self._parseMultiMixArgs(arguments);
  1366. self._execAction('multiMix', 0, arguments);
  1367. if(!self._mixing){
  1368. if(self.controls.enable && !self._clicking){
  1369. self.controls.toggleFilterButtons && self._buildToggleArray();
  1370. self._updateControls(args.command, self.controls.toggleFilterButtons);
  1371. }
  1372. (self._queue.length < 2) && (self._clicking = false);
  1373. delete self.callbacks._user;
  1374. if(args.callback) self.callbacks._user = args.callback;
  1375. var sort = args.command.sort,
  1376. filter = args.command.filter,
  1377. changeLayout = args.command.changeLayout;
  1378. self._refresh();
  1379. if(sort){
  1380. self._newSort = self._parseSort(sort);
  1381. self._newSortString = sort;
  1382. self._sorting = true;
  1383. self._sort();
  1384. }
  1385. if(filter !== undf){
  1386. filter = (filter === 'all') ? self.selectors.target : filter;
  1387. self._activeFilter = filter;
  1388. }
  1389. self._filter();
  1390. if(changeLayout){
  1391. self._newDisplay = (typeof changeLayout === 'string') ? changeLayout : changeLayout.display || self.layout.display;
  1392. self._newClass = changeLayout.containerClass || '';
  1393. if(
  1394. self._newDisplay !== self.layout.display ||
  1395. self._newClass !== self.layout.containerClass
  1396. ){
  1397. self._changingLayout = true;
  1398. self._changingClass = (self._newClass !== self.layout.containerClass);
  1399. self._changingDisplay = (self._newDisplay !== self.layout.display);
  1400. }
  1401. }
  1402. self._$targets.css(self._brake);
  1403. self._goMix(args.animate ^ self.animation.enable ? args.animate : self.animation.enable);
  1404. self._execAction('multiMix', 1, arguments);
  1405. } else {
  1406. if(self.animation.queue && self._queue.length < self.animation.queueLimit){
  1407. self._queue.push(arguments);
  1408. (self.controls.enable && !self._clicking) && self._updateControls(args.command);
  1409. self._execAction('multiMixQueue', 1, arguments);
  1410. } else {
  1411. if(typeof self.callbacks.onMixBusy === 'function'){
  1412. self.callbacks.onMixBusy.call(self._domNode, self._state, self);
  1413. }
  1414. self._$container.trigger('mixBusy', [self._state, self]);
  1415. self._execAction('multiMixBusy', 1, arguments);
  1416. }
  1417. }
  1418. },
  1419. /**
  1420. * Insert
  1421. * @since 2.0.0
  1422. * @param {array} arguments
  1423. */
  1424. insert: function(){
  1425. var self = this,
  1426. args = self._parseInsertArgs(arguments),
  1427. callback = (typeof args.callback === 'function') ? args.callback : null,
  1428. frag = document.createDocumentFragment(),
  1429. target = (function(){
  1430. self._refresh();
  1431. if(self._$targets.length){
  1432. return (args.index < self._$targets.length || !self._$targets.length) ?
  1433. self._$targets[args.index] :
  1434. self._$targets[self._$targets.length-1].nextElementSibling;
  1435. } else {
  1436. return self._$parent[0].children[0];
  1437. }
  1438. })();
  1439. self._execAction('insert', 0, arguments);
  1440. if(args.$object){
  1441. for(var i = 0; i < args.$object.length; i++){
  1442. var el = args.$object[i];
  1443. frag.appendChild(el);
  1444. frag.appendChild(document.createTextNode(' '));
  1445. }
  1446. self._$parent[0].insertBefore(frag, target);
  1447. }
  1448. self._execAction('insert', 1, arguments);
  1449. if(typeof args.multiMix === 'object'){
  1450. self.multiMix(args.multiMix, callback);
  1451. }
  1452. },
  1453. /**
  1454. * Prepend
  1455. * @since 2.0.0
  1456. * @param {array} arguments
  1457. */
  1458. prepend: function(){
  1459. var self = this,
  1460. args = self._parseInsertArgs(arguments);
  1461. self.insert(0, args.$object, args.multiMix, args.callback);
  1462. },
  1463. /**
  1464. * Append
  1465. * @since 2.0.0
  1466. * @param {array} arguments
  1467. */
  1468. append: function(){
  1469. var self = this,
  1470. args = self._parseInsertArgs(arguments);
  1471. self.insert(self._state.totalTargets, args.$object, args.multiMix, args.callback);
  1472. },
  1473. /**
  1474. * Get Option
  1475. * @since 2.0.0
  1476. * @param {string} string
  1477. * @return {mixed} value
  1478. */
  1479. getOption: function(string){
  1480. var self = this,
  1481. getProperty = function(obj, prop){
  1482. var parts = prop.split('.'),
  1483. last = parts.pop(),
  1484. l = parts.length,
  1485. i = 1,
  1486. current = parts[0] || prop;
  1487. while((obj = obj[current]) && i < l){
  1488. current = parts[i];
  1489. i++;
  1490. }
  1491. if(obj !== undf){
  1492. return obj[last] !== undf ? obj[last] : obj;
  1493. }
  1494. };
  1495. return string ? self._execFilter('getOption', getProperty(self, string), arguments) : self;
  1496. },
  1497. /**
  1498. * Set Options
  1499. * @since 2.0.0
  1500. * @param {object} config
  1501. */
  1502. setOptions: function(config){
  1503. var self = this;
  1504. self._execAction('setOptions', 0, arguments);
  1505. typeof config === 'object' && $.extend(true, self, config);
  1506. self._execAction('setOptions', 1, arguments);
  1507. },
  1508. /**
  1509. * Get State
  1510. * @since 2.0.0
  1511. * @return {object} state
  1512. */
  1513. getState: function(){
  1514. var self = this;
  1515. return self._execFilter('getState', self._state, self);
  1516. },
  1517. /**
  1518. * Force Refresh
  1519. * @since 2.1.2
  1520. */
  1521. forceRefresh: function(){
  1522. var self = this;
  1523. self._refresh(false, true);
  1524. },
  1525. /**
  1526. * Destroy
  1527. * @since 2.0.0
  1528. * @param {boolean} hideAll
  1529. */
  1530. destroy: function(hideAll){
  1531. var self = this,
  1532. filters = $.MixItUp.prototype._bound._filter,
  1533. sorts = $.MixItUp.prototype._bound._sort;
  1534. self._execAction('destroy', 0, arguments);
  1535. self._$body
  1536. .add($(self.selectors.sort))
  1537. .add($(self.selectors.filter))
  1538. .off('.mixItUp');
  1539. for(var i = 0; i < self._$targets.length; i++){
  1540. var target = self._$targets[i];
  1541. hideAll && (target.style.display = '');
  1542. delete target.mixParent;
  1543. }
  1544. self._execAction('destroy', 1, arguments);
  1545. if(filters[self.selectors.filter] && filters[self.selectors.filter] > 1) {
  1546. filters[self.selectors.filter]--;
  1547. } else if(filters[self.selectors.filter] === 1) {
  1548. delete filters[self.selectors.filter];
  1549. }
  1550. if(sorts[self.selectors.sort] && sorts[self.selectors.sort] > 1) {
  1551. sorts[self.selectors.sort]--;
  1552. } else if(sorts[self.selectors.sort] === 1) {
  1553. delete sorts[self.selectors.sort];
  1554. }
  1555. delete $.MixItUp.prototype._instances[self._id];
  1556. }
  1557. };
  1558. /* jQuery Methods
  1559. ---------------------------------------------------------------------- */
  1560. /**
  1561. * jQuery .mixItUp() method
  1562. * @since 2.0.0
  1563. * @extends $.fn
  1564. */
  1565. $.fn.mixItUp = function(){
  1566. var args = arguments,
  1567. dataReturn = [],
  1568. eachReturn,
  1569. _instantiate = function(domNode, settings){
  1570. var instance = new $.MixItUp(),
  1571. rand = function(){
  1572. return ('00000'+(Math.random()*16777216<<0).toString(16)).substr(-6).toUpperCase();
  1573. };
  1574. instance._execAction('_instantiate', 0, arguments);
  1575. domNode.id = !domNode.id ? 'MixItUp'+rand() : domNode.id;
  1576. if(!instance._instances[domNode.id]){
  1577. instance._instances[domNode.id] = instance;
  1578. instance._init(domNode, settings);
  1579. }
  1580. instance._execAction('_instantiate', 1, arguments);
  1581. };
  1582. eachReturn = this.each(function(){
  1583. if(args && typeof args[0] === 'string'){
  1584. var instance = $.MixItUp.prototype._instances[this.id];
  1585. if(args[0] === 'isLoaded'){
  1586. dataReturn.push(instance ? true : false);
  1587. } else {
  1588. var data = instance[args[0]](args[1], args[2], args[3]);
  1589. if(data !== undf)dataReturn.push(data);
  1590. }
  1591. } else {
  1592. _instantiate(this, args[0]);
  1593. }
  1594. });
  1595. if(dataReturn.length){
  1596. return dataReturn.length > 1 ? dataReturn : dataReturn[0];
  1597. } else {
  1598. return eachReturn;
  1599. }
  1600. };
  1601. /**
  1602. * jQuery .removeStyle() method
  1603. * @since 2.0.0
  1604. * @extends $.fn
  1605. */
  1606. $.fn.removeStyle = function(style, prefix){
  1607. prefix = prefix ? prefix : '';
  1608. return this.each(function(){
  1609. var el = this,
  1610. styles = style.split(' ');
  1611. for(var i = 0; i < styles.length; i++){
  1612. for(var j = 0; j < 4; j++){
  1613. switch (j) {
  1614. case 0:
  1615. var prop = styles[i];
  1616. break;
  1617. case 1:
  1618. var prop = $.MixItUp.prototype._helpers._camelCase(prop);
  1619. break;
  1620. case 2:
  1621. var prop = prefix+styles[i];
  1622. break;
  1623. case 3:
  1624. var prop = $.MixItUp.prototype._helpers._camelCase(prefix+styles[i]);
  1625. }
  1626. if(
  1627. el.style[prop] !== undf &&
  1628. typeof el.style[prop] !== 'unknown' &&
  1629. el.style[prop].length > 0
  1630. ){
  1631. el.style[prop] = '';
  1632. }
  1633. if(!prefix && j === 1)break;
  1634. }
  1635. }
  1636. if(el.attributes && el.attributes.style && el.attributes.style !== undf && el.attributes.style.value === ''){
  1637. el.attributes.removeNamedItem('style');
  1638. }
  1639. });
  1640. };
  1641. })(jQuery);