PageSourceSearch

https://mangiacateringco.com/wp-content/plugins/the-grid/frontend/assets/js/the-grid.js?ver=2.5.0

js mangiacateringco.com collected 2026-10-05 21:26:19 UTC 74,258 bytes, 2,266 lines download raw bytes

1/*!
2 * The Grid – Core jQuery Plugin
3 * Copyright © 2015 All Rights Reserved. 
4 * @author Themeone [http://theme-one.com/the-grid/]
5 */
6
7/*global jQuery:false*/
8/*global tg_global_var:false*/
9/*global SC:false*/
10/*global YT:false*/
11/*global $f:false*/
12/*global mejs*/
13/*global TG_Slider:false*/
14/*global TG_metaData*/
15/*global TG_excludeItem*/
16/*global FOOBOX*/
17/*func = shorthand if function */
18
19jQuery.noConflict();
20
21// The Grid default settings
22var The_Grid = {
23	preview : '#tg-grid-preview-inner',
24	wrapper : '.tg-grid-wrapper',
25	slider  : '.tg-grid-slider',
26	grid    : '.tg-grid-holder',
27	loader  : '.tg-grid-preloader',
28	ajax    : '.tg-ajax-button',
29	ajaxMsg : '.tg-ajax-scroll-holder',
30	sizer   : '.tg-grid-sizer',
31	gutter  : '.tg-gutter-sizer',
32	item    : '.tg-item',
33	itemImg : '.tg-item-image',
34	gallery : '.tg-item-gallery-holder',
35	tooltip : '.tg-filter-count',
36	filterH : '.tg-filters-holder',
37	filter  : '.tg-filter, .tg-filters-holder select',
38	search  : '.tg-search',
39	clear   : '.tg-search-clear',
40	sorter  : '.tg-sorters-holder',
41	sorterBy: '.tg-sorter li, select.tg-sorter',
42	sortASC : '.tg-sorter-order',
43	arrLeft : '.tg-left-arrow',
44	arrRight: '.tg-right-arrow',
45	bullets : '.tg-slider-bullets',	
46	pages   : '.tg-page-ajax',
47	sortData: {
48		excerpt : 'p',
49		title   : function(elem) {
50        	return jQuery(elem).data('title');
51      	},
52		id      : function(elem) {
53        	return jQuery(elem).data('id');
54      	},
55		date    : function(elem) {
56        	return jQuery(elem).data('date');
57      	},
58		author  : function(elem) {
59        	return jQuery(elem).data('author');
60      	},
61		comment : function(elem) {
62        	return jQuery(elem).data('comment');
63      	},
64		popular_post : function(elem) {
65        	return jQuery(elem).data('popular-post');
66      	},
67		total_sales   : function(elem) {
68        	return jQuery(elem).data('total-sales');
69      	},
70		regular_price : function(elem) {
71        	return jQuery(elem).data('regular-price');
72      	},
73		sale_price : function(elem) {
74        	return jQuery(elem).data('sale-price');
75      	},
76		featured   : function(elem) {
77        	return jQuery(elem).data('featured');
78      	},
79		stock      : function(elem) {
80        	return jQuery(elem).data('stock');
81      	},
82		sku        : function(elem) {
83        	return jQuery(elem).data('sku');
84      	}
85	},
86    defaults: {
87		//init       : function() {},
88		//relayout   : function() {},
89		style      : 'grid',
90		layout     : 'vertical',
91		fitrows    : false,
92		fullWidth  : null,
93		fullHeight : null,
94		rtl        : true,
95		filterComb : false,
96		filterLogic: 'AND',
97		filterLoad : '',
98		sortByLoad : '',
99		orderLoad  : false,
100		row        : 1,
101		ratio      : 1,
102		gutters    : [[9999,0],[1200,0],[980,0],[768,0],[480,0],[320,0]],
103        cols       : [[9999,4],[1200,3],[980,3],[768,2],[480,1],[320,1]],
104		rows       : [[9999,240],[1200,240],[980,220],[768,220],[480,200],[320,200]],
105		animation  : [{'name':'None'},{'visible':''},{'hidden':''}],
106		transition : 0,
107		itemNav    : null,
108		swingSpeed : 500,
109		cycleBy    : null,
110		cycle      : 5000,
111		startAt    : 0,
112		ajaxMethod : null,
113		ajaxDelay  : 0,
114		preloader  : 0,
115		itemDelay  : 0,
116		gallery    : false
117    }
118};
119
120// Extend sortby with custom metadata
121var tg_meta_data = tg_global_var.meta_data;
122var tg_custom_sorter = {};
123if (tg_meta_data) {
124	for (var i = 0; i < tg_meta_data.length; i++) {
125		var tg_cmk = tg_meta_data[i].key;
126		tg_cmk = (tg_cmk.length && tg_cmk[0] == '_') ? tg_cmk.slice(1) : tg_cmk;
127		var tg_cma = tg_cmk.replace(/\_/g, '-');
128		(function(tg_cma){
129			tg_custom_sorter[tg_cmk] = function(elem) {
130				return jQuery(elem).data(tg_cma);
131			};
132		})(tg_cma);
133	}
134}
135// add new custom sorter to the grid
136The_Grid.sortData = jQuery.extend({}, The_Grid.sortData, tg_custom_sorter);
137
138var tg_debounce_resize = (tg_global_var.debounce) ? 'debouncedresize' : 'resize'; // debounce resize functionnality
139var tg_is_mobile = (tg_global_var.is_mobile); // check is we are on a mobile device
140
141(function($) {
142				
143	"use strict";
144	
145	// the grid jquery plugin
146	$.fn.The_Grid = function(options) {
147		
148		// Loop foreach grid (multi instance)
149		return this.each(function () {
150			
151			// current grid
152			var el = $(this);
153
154			// main grid var
155			var revealItems,
156				buttonFilter,
157				sortByValue,
158				sortByName,
159				rand1,
160				index1,
161				index2,
162				gallery_imgs = [],
163				sortOrder = true,
164				item_nb = true,
165				isInit = false,
166				isAjax = false,
167				page = 1,
168				$frame,
169				gutter,
170				itemW,
171				itemH,
172				colR,
173				colN,
174				colW,
175				colH,
176				offs,
177				realW,
178				func,
179				xhr = null;
180			
181			// define main DOM
182			var ID        = el.closest(The_Grid.wrapper).attr('id'),
183				$wrapper  = ($('[id="'+ID+'"]').length > 1) ? el.closest(The_Grid.wrapper) : $('#'+ID),
184				$preview  = $wrapper.closest(The_Grid.preview),
185				$slider   = $wrapper.find(The_Grid.slider),
186				$loader   = $wrapper.find(The_Grid.loader),
187				$ajax     = $wrapper.find(The_Grid.ajax),
188				$ajaxMsg  = $wrapper.find(The_Grid.ajaxMsg),
189				$sizer    = $wrapper.find(The_Grid.sizer),
190				$gutter   = $wrapper.find(The_Grid.gutter),
191				$item     = $wrapper.find(The_Grid.item),
192				$filterH  = $wrapper.find(The_Grid.filterH),
193				$filter   = $wrapper.find(The_Grid.filter),
194				$search   = $wrapper.find(The_Grid.search),
195				$clear    = $wrapper.find(The_Grid.clear),
196				$sorter   = $wrapper.find(The_Grid.sorter),
197				$sorterBy = $wrapper.find(The_Grid.sorterBy),
198				$sortASC  = $wrapper.find(The_Grid.sortASC),
199				$arrLeft  = $wrapper.find(The_Grid.arrLeft),
200				$arrRight = $wrapper.find(The_Grid.arrRight),
201				$bullets  = $wrapper.find(The_Grid.bullets),
202				$pages    = $wrapper.find(The_Grid.pages);
203
204			// retireve all data
205			var data = el.data();
206
207			// get grid settings (check for existing key in case php errors)
208			var settings = {
209				//init        : options.init,
210				//relayout    : options.relayout,
211				style       : (data.style)       && data.style,
212				layout      : (data.layout)      && data.layout,
213				fitrows     : (data.fitrows)     && data.fitrows,
214				fullWidth   : (data.fullwidth)   && data.fullwidth,
215				fullHeight  : (data.fullheight)  && data.fullheight,
216				rtl         : (data.rtl)         && data.rtl,
217				filterComb  : (data.filtercomb)  && data.filtercomb,
218				filterLogic : (data.filterlogic) && data.filterlogic,
219				filterLoad  : (data.filterload)  && data.filterload,
220				sortByLoad  : (data.sortbyload)  && data.sortbyload,
221				orderLoad   : (data.orderload)   && data.orderload,
222				row         : (data.row)         && data.row,
223				ratio       : (data.ratio)       && data.ratio,
224				gutters     : (data.gutters)     && data.gutters,
225				cols        : (data.cols)        && data.cols,
226				rows        : (data.rows)        && data.rows,
227				animation   : (data.animation)   && data.animation,
228				transition  : (data.transition)  && data.transition,
229				itemNav     : (data.slider)      && data.slider.itemNav,
230				swingSpeed  : (data.slider)      && data.slider.swingSpeed,
231				cycleBy     : (data.slider)      && data.slider.cycleBy,
232				cycle       : (data.slider)      && data.slider.cycle,
233				startAt     : (data.slider)      && data.slider.startAt,
234				ajaxMethod  : (data.ajaxmethod)  && data.ajaxmethod,
235				ajaxDelay   : (data.ajaxdelay)   && data.ajaxdelay,
236				preloader   : (data.preloader)   && data.preloader,
237				itemDelay   : (data.itemdelay)   && data.itemdelay,
238				gallery     : (data.gallery)     && data.gallery,
239			};
240
241			// check/set settings compare to default grid
242			var options = $.extend({},The_Grid.defaults, settings);
243			// sort cols array desc numeric (for futur column number detection)
244			options.cols.sort(function(a, b){return b[0]-a[0];});
245			// sort gutters array desc numeric (for futur rows height detection)
246			options.gutters.sort(function(a, b){return b[0]-a[0];});
247			// sort rows array desc numeric (for futur rows height detection)
248			options.rows.sort(function(a, b){return b[0]-a[0];});
249			// set correct value for RTL layout
250			options.rtl = (options.rtl) ? false : true;
251			// Ajax pagination get same delay on reveal
252			options.ajaxDelay = ($pages.length > 0) ? options.itemDelay : options.ajaxDelay;
253			// remove all data for security and confidentiality
254			var keys = $.map(data, function(value, key) { return key; });
255			for (var i = 0; i < keys.length; i++) {
256				el.removeAttr('data-' + keys[i]);
257			}
258
259			// build the grid
260			full_width();   // 1. resize the grid wrapper at first
261			columns(el);    // 2. then calculate the columns width based on the wrapper width
262			item_size();    // 3. set the sizes to each item based on the column width			
263			item_gallery(); // 4. init item gallery animation
264			count_filter(); // 5. count and update filter number if necessary
265
266			// set the grid size after everything loaded in masonry mode to relayout correctly
267			if (options.style === 'masonry' || options.style === 'justified' || options.preloader || options.layout === 'horizontal') {
268				$item.the_grid_images_loaded({
269					complete: function() {
270						slider_size();   // 7. calculate slider height if necessary
271						set_grid();      // 8. check grid parameters values
272						init_slider();   // 9. init slider if available
273						func = (options.preloader) && reveal_grid();
274						// call on filtering, sorting, searching, and resizing  after complete
275						func = (options.layout === 'horizontal') && el.TG_Layout('on', 'arrangeComplete', function(e) {onAnimationEnd(e);});  // filter/sort	
276						// run the init callback method
277						//func = (typeof options.init == 'function') && options.init.call(el);
278					}
279				});
280			} else {
281				set_grid();    // 7. check grid parameters values
282				init_slider(); // 8. init slider if available
283				// call on filtering, sorting, searching, and resizing  after complete
284				func = (options.layout === 'horizontal') && el.TG_Layout('on', 'arrangeComplete', function(e) {onAnimationEnd(e);});  // filter	/sort
285			}
286			
287			// all events init
288			isInit = (!options.preloader) &&  true;
289			func = (isInit) && $wrapper.addClass('tg-grid-loaded');
290
291			function onAnimationEnd(e) {
292				var length = $item.not('.tg-item-hidden').length;
293				if (e.length === length) {
294					$frame.reload();
295				}
296			}
297			
298			// redefined and remove/clean data
299			function cleanData(target) {
300				for (var y = 0; y < $(target).length; y++) {
301					var $this = $(target).eq(y), key, val,
302						data  = $this.get(0).attributes;	
303					for (var i = 0; i < data.length; i++) {
304						key = data[i].name;
305						val = data[i].value;
306						if (key.indexOf('data-') === 0 && key !== 'data-row' && key !== 'data-col') {
307							$this.removeAttr(key);
308							$this.data(key.replace('data-',''),val);
309							i--;
310						}
311					}
312				}
313			}
314			
315			// detect dropdown select list on touch devices
316			$filter.on('click', function(e) {
317				var $this = $(this);
318				if (!$this.is('select')) {
319					filterBy($this);
320				} else {
321					$filter.one('change', function() {
322						filterBy($this.find('option:selected'));
323					});
324				}
325				// run the layout callback method
326				//func = (typeof options.relayout == 'function') && el.TG_Layout('once', 'layoutComplete', function(e) {options.relayout.call(el);});
327			});		
328			
329			function filterBy($this) {
330				if (!isInit) {
331					return false;
332				}
333				var filterValue;
334				// remove class reveal and clear seach field before filtering
335				$item.removeClass('tg-item-index');
336				$search.val('');
337				// check if filter combination or not
338				if (options.filterComb) {
339					filterValue = [];
340					func = ($this.data('filter') === '*') ? $this.nextAll('[data-filter]').removeClass('tg-filter-active') : $this.prevAll('[data-filter="*"]').removeClass('tg-filter-active');
341					func = ($this.data('filter') === '*') ? $this.closest('select').find('option').prop('selected', false) : $this.closest('select').find('[data-filter="*"]').prop('selected', true);	
342					$this.toggleClass('tg-filter-active');
343					$wrapper.find('.tg-filter-active').each(function(){
344						if ($(this).data('filter') != '*') {
345							filterValue.push($(this).data('filter'));
346						}
347					});
348					filterValue = (options.filterLogic === 'AND') ? concatValues(filterValue) : filterValue.join(', ');
349				} else {
350					filterValue = $this.data('filter');
351					$filter.removeClass('tg-filter-active');
352					$this.addClass('tg-filter-active');
353				}
354				func = (!filterValue) && $wrapper.find('[data-filter="*"]').addClass('tg-filter-active');
355				checkFilters();
356				// apply filter(s)
357				el.TG_Layout({filter: filterValue});
358				// pause all videos
359				$.TG_Pause_Players();		
360			}
361			
362			function concatValues( obj ) {
363				var value = '';
364				for ( var prop in obj ) {
365					if(obj.hasOwnProperty(prop)) {
366						value += obj[ prop ];
367					}
368				}
369				return value;
370			}
371			
372			function checkFilters() {
373				$filterH.each(function(index, element) {
374                    var nbActive = $(this).find(The_Grid.filter+'.tg-filter-active').length;
375					func = (nbActive === 0) && $(this).find('[data-filter="*"]').addClass('tg-filter-active');	
376                });
377			}
378
379			if (!tg_is_mobile) {
380				$sorterBy.on('click', function() {
381					sortBy($(this));
382				});
383			} else {
384				$sorterBy.on('change', function() {
385					sortBy($(this).find('option:selected'));
386				});
387			}
388			
389			function sortBy(il) {
390				if (!isInit) {
391					return false;
392				}
393				sortByValue = (il.data('value') === 'none') ? '' : il.data('value');
394				sortByName  = il.text();
395				sortOrder   = $sortASC.data('asc');
396				$item.removeClass('tg-item-index');
397				$sorter.find('.tg-dropdown-value').text(sortByName);
398				el.TG_Layout({
399					sortAscending: sortOrder,
400					sortBy: sortByValue 
401				});
402				// run the layout callback method
403				//func = (typeof options.relayout == 'function') && el.TG_Layout('once', 'layoutComplete', function(e) {options.relayout.call(el);});
404			}
405			
406			// TG_Layout sorter functionnality (ASC/DESC only)
407			$sortASC.on('click', function() {
408				if (!isInit) {
409					return false;
410				}
411				var $this   = $(this);
412				sortOrder = ($this.data('asc') === true) ? false : true;
413				$this.data('asc',sortOrder).attr('data-asc',sortOrder);
414				$item.removeClass('tg-item-index');
415				el.TG_Layout({
416					sortAscending: sortOrder
417				});
418				// run the layout callback method
419				//func = (typeof options.relayout == 'function') && el.TG_Layout('once', 'layoutComplete', function(e) {options.relayout.call(el);});
420			});
421			
422			// use value of search field to filter (regex in content)
423			var $quicksearch = $search.keyup( debounce( function() {
424				if (!isInit) {
425					return false;
426				}
427				var qsRegex = new RegExp($quicksearch.val(), 'gi');
428				$item.removeClass('tg-item-index');
429				$filter.removeClass('tg-filter-active');
430				el.TG_Layout({
431					filter: function() { 
432						var $this = $(this);
433						var searchResult = qsRegex ? $this.text().match(qsRegex) : true;
434						var buttonResult = buttonFilter ? $this.is(buttonFilter) : true;						
435						$('.tg-filter[data-filter="*"]').addClass('tg-filter-active');
436						return searchResult && buttonResult;
437					}
438				});
439				// pause all videos
440				$.TG_Pause_Players();
441				// run the layout callback method
442				//func = (typeof options.relayout == 'function') && options.relayout.call(el)
443			}, 200));
444			
445			$clear.on('click', function() {
446				$search.val('').trigger('keyup');
447				// run the layout callback method
448				//func = (typeof options.relayout == 'function') && el.TG_Layout('once', 'layoutComplete', function(e) {options.relayout.call(el);});
449			});
450			
451			// resize grids
452			$(window).on(tg_debounce_resize, function() {
453				full_width();  // 1. resize the grid wrapper at first
454				columns();     // 2. then calculate the column width based on the wrapper width
455				item_size();   // 3. set size to items based on the column width
456				slider_size(); // 4. calculate slider height if necessary
457				// 5. Relayout the grid
458				func = (isInit && el.closest('body').length > 0) && el.TG_Layout('layout');
459				// 6. Check animation end for horizontal layout to update slider
460				func = (options.layout === 'horizontal') && el.TG_Layout('once', 'layoutComplete', function(e) {onAnimationEnd(e);});
461				// run the layout callback method
462				//func = (typeof options.relayout == 'function') && el.TG_Layout('once', 'layoutComplete', function(e) {options.relayout.call(el);});
463			});
464			
465			// force full width
466			function full_width() {
467				if (options.fullWidth && $preview.length === 0) {
468					$wrapper.css('left',0);
469					var margL = parseInt($wrapper.css('margin-left'));
470					var margR = parseInt($wrapper.css('margin-right'));
471					var offset = $wrapper.offset().left-margL;
472					$wrapper.width($(window).width()-(margL+margR));
473					$wrapper.css('left',-offset);
474				}
475			}
476			
477			// random item gallery animation
478			function item_gallery() {
479				if (options.gallery) {
480					var gallery;
481					update_gallery();
482					if (!The_Grid.galleryInt && $(The_Grid.gallery).length > 0 ) {
483						The_Grid.galleryInt = setInterval(function () {
484							rand1   = Math.floor(Math.random()*gallery_imgs.length);
485							index1  = (index1 === rand1 && gallery_imgs.length > 0) ? check_index(gallery_imgs,rand1+1) : rand1;
486							gallery = $(The_Grid.gallery).eq(index1);
487							index2  = (gallery_imgs.length > 0) ? check_index(gallery_imgs[index1],(gallery.find('.show').index()-1)+2) : 0;
488							gallery.find(The_Grid.itemImg).removeClass('show');
489							gallery.find(The_Grid.itemImg).eq(index2).addClass('show');
490						},3500);
491					}
492				}
493			}
494			
495			// check image gallery index for unique random
496			function check_index(array,index) {
497				return (array.length + (index % array.length)) % array.length;
498			}
499			
500			// get all galleries
501			function update_gallery() {
502				gallery_imgs = [];
503				var galleries = $(The_Grid.gallery);
504				for (var i = 0; i < galleries.length; i++) {
505					var images = $(galleries[i]).find(The_Grid.itemImg);
506					gallery_imgs[i] = [];
507					for (var x = 0; x < images.length; x++) {
508                     	gallery_imgs[i][x] = $(images[x]);   
509                    }
510				}
511			}
512			
513			// count number per filter category/tag/term
514			function count_filter() {
515				for (var i = 0; i < $filter.length; i++) {
516					var cat   = $filter.eq(i).data('filter');
517					// if ajax page not count elements removing
518					var not = ($pages.length > 0) ? '.tg-item-hidden' : null;
519					var count = (cat !== '*') ? el.find(cat).not(not).length : $item.not(not).length;
520					$filter.eq(i).find(The_Grid.tooltip).html(count);
521					func = ($filter.eq(i).find('span:first-child').data('count')) && $filter.eq(i).find('span:first-child').data('tooltip',count);
522					func = (count === 0) ? $filter.eq(i).removeClass('tg-show-filter') : $filter.eq(i).addClass('tg-show-filter');
523				}
524			}
525			
526			// count item to load more
527			function count_items() {
528				if ($ajax.length > 0) {
529					item_nb = ($ajax.data('item-tt')) ? $ajax.data('item-tt')-$item.length : 99999;
530					if (item_nb <= 0) {
531						$ajax.addClass('tg-no-more');
532						$ajax.find('span').html($ajax.data('no-more'));
533						setTimeout(function(){
534							$ajax.fadeOut(500);
535						},3000);
536					} else {
537						var button_txt = $ajax.data('button');
538						func = ($ajax.data('remain')) ? $ajax.find('span').html(button_txt+' ('+item_nb+')') : $ajax.find('span').html(button_txt);
539					}
540				}
541			}	
542			
543			// reveal grid on load
544			function reveal_grid() {
545				var i = 0,
546					interval,
547					data = el.data('TG_Layout');
548				func = ($pages.length === 0) ? $loader.remove() : $loader.hide();
549				$wrapper.removeClass('tg-grid-loading');
550				revealItems = data.filteredItems;
551				if (revealItems.length > 0) {
552					interval = window.tgInterval(function(){
553						if (el.closest('body').length > 0) {
554							$(revealItems[i].element).removeClass('tg-item-reveal');
555							func = (options.itemDelay) && el.TG_Layout('reveal', [revealItems[i]]);	
556							if (i === revealItems.length-1 || !options.itemDelay) {
557								isInit = true;
558								$item.removeClass('tg-item-reveal');
559								$wrapper.addClass('tg-grid-loaded');
560								func = (!options.itemDelay) && el.TG_Layout('reveal', revealItems);
561								interval.clear();	
562							}
563							i++;
564						}
565					},options.itemDelay);
566				} else {
567					isInit = true;
568					$item.removeClass('tg-item-reveal');
569					$wrapper.addClass('tg-grid-loaded');
570				}
571			}
572			
573			// Calculate column width number for current window width
574			function columns() {
575				var arr = (options.style !== 'justified') ? options.cols : options.rows;
576				var ww = viewport().width;
577				for (var i = 0, l = arr.length; i < l; i++ ) {
578					if (arr[i][0] >= ww) {
579						colN = arr[i][1];
580						gutter = options.gutters[i][1];
581					} else {
582						break;
583					}
584				}
585				// set gutters
586				$gutter.width(gutter);
587				if (options.style !== 'justified') {
588					var tw = $wrapper.width();
589					colW = (tw/colN) - gutter;
590					if (options.layout === 'vertical') {
591						el.width('');
592						offs  = (colN-1)*gutter;
593						colW  = (tw-offs)/colN;
594						colW  = (colW % 1 !== 0) ? Math.ceil(colW) : colW;
595						realW = colN*colW+offs;
596						el.css('left', -(realW-el.width())/2+'px');
597						el.width(realW);
598					}
599					if (options.fullHeight && options.layout === 'horizontal') {
600						var adminH = $('#wpadminbar').height();
601						if ($preview.length === 0) {
602							colH = (($(window).height()-adminH)-(gutter*(options.row-1)))/options.row;
603						} else {
604							colH = ($preview.height())/options.row;
605						}
606					} else {
607						// round for accurate slider height (no need for width!)
608						colH = Math.round(colW/options.ratio);
609					}
610				} else {
611					// justified row height is colH
612					colH = colN;
613					$sizer.height(colH);	
614				}
615				// add slider padding if free mode
616				func = (options.itemNav === 'null') && $slider.css('padding', '0 '+gutter/2+'px');
617			}
618			
619			// calculate window viewport (real width to match queries!)
620			function viewport() {
621				if ($preview.length === 0) {
622					var e = window,
623						a = 'inner';
624					if (!('innerWidth' in window )) {
625						a = 'client';
626						e = document.documentElement || document.body;
627					}
628					return { width : e[ a+'Width' ]};
629				} else {
630					return { width : $preview.width()};
631				}
632			}
633			
634			// calculate item size and resize if necessary (unlimited size possibility!)
635			function item_size() {
636				if (options.style !== 'justified') {
637					// set grid sizer
638					$sizer.width(colW);
639					for (var i = 0; i < $item.length; i++) {
640						var coli = $item.eq(i).data('col'),
641							rowi = $item.eq(i).data('row');
642							rowi = ((options.layout === 'horizontal') && rowi > options.row) ? options.row : rowi;
643						if (colN === 1) {
644							itemW = colW;
645							itemH = colH;
646						} else if (colN < coli) {
647							colR  = Math.round(colN/(coli/rowi));
648							colR  = (colR <= 1) ? 1 : colR;
649							itemW = colN*colW+(colN-1)*gutter;
650							itemH = (colR === 1) ? colH : colR*colH+(colR-1)*gutter;
651						} else {
652							itemW = coli*colW+(coli-1)*gutter;
653							itemH = rowi*colH+(rowi-1)*gutter;
654						}
655						$item.eq(i).width(itemW);
656						func = (options.style === 'grid') ? $item.eq(i).height(itemH) : null;
657					}
658				}
659			}
660			
661			// calculate slider inner height
662			function slider_size() {
663				if (options.layout === 'horizontal') {
664					var sliderH;
665					if (options.style === 'masonry') {
666						$wrapper.removeClass('tg-grid-loading');
667						// only when all images are loaded to get right height in masonry mode
668						sliderH = Math.max.apply(null, $item.map(function () {
669							return $(this).height();
670						}).get());
671						el.add($slider).height(sliderH);
672					} else {
673						sliderH = (colH)*options.row+gutter*(options.row-1);
674						el.add($slider).height(sliderH);
675					}
676				}
677			}
678			
679			// set the grid
680			function set_grid() {
681				var mode, param;
682				var isHorizontal = false;
683				if (options.layout === 'horizontal') {
684					isHorizontal = true;
685					if (options.style === 'grid') {
686						mode = param = 'packery';
687					} else if (options.style === 'justified'){
688						mode = param = 'justified';
689					} else {
690						mode = param = 'horizontal';
691					}
692				} else if (options.style === 'grid') {
693					mode = param = 'packery';
694				} else {
695					mode = param = options.style;
696				}
697				var layout = {};			
698				layout[param] = {};
699				layout.hiddenStyle = {};
700				layout.visibleStyle = {};
701				layout.layoutMode = mode;
702				layout.filter = options.filterLoad;
703				if (options.sortByLoad !== 'none') {
704					layout.sortBy = options.sortByLoad;
705				}
706				layout.sortAscending = options.orderLoad;
707				layout.isOriginLeft = options.rtl;
708				layout.itemSelector = The_Grid.item;
709				layout[param].gutter = $gutter[0];
710				layout[param].rowHeight = $sizer[0];
711				layout[param].columnWidth = $sizer[0];
712				layout[param].isHorizontal = isHorizontal;
713				layout[param].isFitRows = options.fitrows;
714				layout[param].image = The_Grid.itemImg;		
715				layout[param].row = options.row;
716				layout[param].previewMode = $preview;
717				layout.hiddenStyle.opacity = 0;
718				layout.visibleStyle.opacity = 1;
719				layout.hiddenStyle.transform = options.animation.hidden;
720				layout.visibleStyle.transform = options.animation.visible;
721				layout.transitionDuration = options.transition;
722				layout.getSortData = The_Grid.sortData;
723				el.TG_Layout(layout);
724				// secure data
725				cleanData($item);
726			}
727
728			// init horizontal slider
729			function init_slider() {	
730				if (options.layout === 'horizontal') {	
731				
732					var data  = el.data('TG_Layout'),
733						filteredItems = data.filteredItems,
734						index = options.startAt = (options.startAt-1 > filteredItems.length) ? filteredItems.length : options.startAt;	
735					
736					if (options.itemNav === 'forceCentered' && $bullets.length === 0) {
737						$bullets = $($('<div class="tg-slider-bullets"></div>')).appendTo($wrapper).hide();
738					}
739								
740					$frame = new TG_Slider($slider,{
741						itemSelector  : '.tg-item:not(.tg-item-hidden)',
742						cycleBy       : options.cycleBy,
743						cycleInterval : options.cycle,
744						pauseOnHover  : 1,
745						itemNav       : options.itemNav,
746						startAt       : options.startAt-1,
747						smart         : 1,
748						horizontal    : 1,
749						easing        : 'easeOutExpo',
750						speed         : 1000,
751						swingSpeed    : options.swingSpeed,
752						releaseSwing  : 1,
753						mouseDragging : 1,
754						touchDragging : 1,
755						elasticBounds : 1,
756						moveBy        : itemW,
757						syncSpeed     : 0.8,
758						keyboardNavBy : 'pages',
759						activeClass   : 'tg-active-item',
760						disabledClass : 'tg-disabled',
761						draggedClass  : 'tg-slider-dragged',
762						pageBuilder   : function () {
763							return '<li><span></span></li>';
764						},
765						pagesBar      : $bullets,
766						prevPage      : $arrLeft,
767						nextPage      : $arrRight,
768						activatePageOn: 'click'
769					}).init();
770					// add event and DOM for slider loaded (for custom event)
771					$slider.data('slider', $frame).trigger('tg-slider-init');
772					
773					// active on force centered nav
774					if (options.itemNav === 'forceCentered') {
775						$(filteredItems[index-1].element).addClass('tg-active-item');
776						$frame.on('load activePage', function(index) {
777							index = this.rel.activePage;
778							data  = el.data('TG_Layout');
779							filteredItems = data.filteredItems;
780							$item.removeClass('tg-active-item');
781							func = (filteredItems[index]) && $(filteredItems[index].element).addClass('tg-active-item');
782						});
783					}
784					
785				}
786			}
787			
788			// load more ajax pagination
789			$pages.on('click', function(e) {
790				e.preventDefault();
791				var $this = $(this);
792				page = $this.data('page');
793				if (!$this.is('.tg-page-current') && (!xhr || (xhr && xhr.readyState == 4)) && !isAjax && isInit) {
794					$sorter.find('.tg-dropdown-value').text('');
795					$search.val('');
796					$filter.removeClass('tg-filter-active');
797					$('.tg-filter[data-filter="*"]').addClass('tg-filter-active');
798					$pages.removeClass('tg-page-current').addClass('tg-loading');
799					$this.addClass('tg-page-current');
800					// prevent showing filtered items when removing them
801					$('.tg-item-hidden').addClass('tg-item-removed');
802					// destroy all media (prevent issue with ajax)
803					$.TG_media_destroy(el);
804					// properly remove items, relayout and unfilter
805					el.css('min-height',250).TG_Layout('remove', $item).TG_Layout({filter: '*'});
806					// remove comments from DOM
807					el.contents().each(function() {func = (this.nodeType == 8) ? $(this).remove() : null;});
808					// add loading animation
809					$loader.show();
810					// load next page
811					load_posts(el);
812				}
813			});
814			
815			// load more ajax on click
816			$ajax.on('click', function(e) {
817				if (item_nb) {
818					e.preventDefault();
819					load_posts(el);
820				}
821			});
822
823			// load more ajax on scroll
824			if (options.ajaxMethod == 'on_scroll') {
825				$(window).on('mousewheel resize scroll', function() {
826					func = (item_nb && $wrapper.length && $wrapper[0].getBoundingClientRect().bottom <  $(this).height() && isInit === true) && load_posts(el);
827				});			
828			}
829			
830			// load more post on ajax (on click and scroll)
831			function load_posts(el){
832
833				// check if ajax request not proceeded and finish before running another one
834				if (xhr && (xhr.readyState == 3 || xhr.readyState == 2 || xhr.readyState == 1)) {
835                	return false;
836            	}
837
838				var ajaxData = { 
839					action     : 'the_grid_load_more', 
840					grid_nonce : tg_global_var.nonce, 
841					grid_name  : el.data('name'),
842					grid_page  : page,
843					grid_data  : get_meta_data(),
844					grid_ajax  : el.data('ajax'),
845					main_query : tg_global_var.main_query
846				};
847
848				xhr = $.ajax({
849					url: tg_global_var.url,
850					type: 'post',
851					datatype : 'json',
852					data: ajaxData,
853					beforeSend : function(){
854						isAjax = true;
855						page   = page + 1;
856						func   = ($ajax.data('loading') && !$ajax.hasClass('tg-no-more')) && $ajax.find('span').html($ajax.data('loading'));
857						func   = ($($ajaxMsg).length > 0 && $ajax.length === 0) && $($ajaxMsg).addClass('tg-loading');			
858					},
859					success : function(data){
860
861						// retrieve ajax response
862						var success   = data.success,
863							message   = data.message,
864							content   = data.content,
865							ajax_data = data.ajax_data;
866
867						// assign new ajax data (check if json)
868						var is_json = true;
869						try {
870							ajax_data = $.parseJSON(ajax_data);
871						} catch(err) {
872							is_json = false;
873						}     
874						el.data('ajax', ajax_data);
875
876						// if an error occur during retrieving content
877						if (!success) {
878							$ajax.add($($ajaxMsg)).add($pages).removeClass('tg-loading');
879							$loader.find('> div').html(message);
880							$ajax.find('span').html(message);
881							$($ajaxMsg).children('div').html(message);
882							page = page - 1;
883							return false;
884						}
885
886						// ajax on scroll msg
887						if (!content) {
888							$ajax.data('item-tt',-1);
889							count_items();
890							$($ajaxMsg).children('div').html($($ajaxMsg).children('div').data('no-more'));
891							setTimeout(function(){
892								$($ajaxMsg).fadeOut(400);
893							}, 1000);
894							page = page - 1;
895							return false;
896						}
897						
898						// get all items
899						var $items = $(content);
900						
901						// prevent showing item if filtered and hidden
902						func = ($pages.length === 0) && $items.addClass('tg-item-index');
903						
904						// Keep only item if unwanted wrapper exist (for grid cache system)
905						if ($items.find(The_Grid.grid).length > 0) {
906							$items = $items.find(The_Grid.item).removeClass('tg-item-reveal');
907						}
908						
909						el.append($items);              // 01. append items
910						$item = el.find(The_Grid.item); // 02. redefined $item DOM
911						$items.hide();			        // 03. hide to append with delay
912						item_size();					// 04. calculate size
913						$.TG_media_init();			    // 05. Active media (visible/sized for mejs)
914						count_filter();	                // 06. re-count filter nb              
915						update_gallery();               // 07. update gallery dom
916						item_gallery();                 // 08. update animated gallery
917						exclude_item();                 // 09. only for preview mode
918
919						// Remove comment tags before items (otherwise it will count 2x and multiply delay)
920						$items = $($.grep($items, function(e){ return typeof e.id !== 'undefined';}));
921						var itemNb = $items.length-1;
922						// wait all images load (mandatory for masonry layout)
923						$items.the_grid_images_loaded({
924							complete: function() {
925								var i = 0, interval;
926								$loader.hide();
927								func = (data) && $($ajaxMsg).removeClass('tg-loading');
928								func = (options.layout === 'horizontal') && el.css('min-height','');
929								func = (options.style === 'masonry' && options.layout === 'horizontal') && slider_size();
930								interval = window.tgInterval(function(){
931									// check if grid still exist during appending (prevent errors on destroy or ajax)
932									if (el.closest('body').length > 0) {	
933										func = (options.ajaxDelay) && el.TG_Layout('appended',$items.eq(i));													
934										func = (options.layout === 'horizontal') && $frame.reload();
935										// show ajax pages & reset ajax
936										if (itemNb === i || !options.ajaxDelay) {
937											count_filter(); // 10. re-count filter nb  
938											count_items();  // 11. re-count item for ajax button
939											func = (!options.ajaxDelay) && el.TG_Layout('appended',$items);
940											func = (options.layout === 'horizontal') && $frame.reload();
941											$pages.removeClass('tg-loading');
942											isAjax = false;
943											interval.clear();
944											// update 3rd party plugins lightbox
945											func = (typeof FOOBOX !== 'undefined' && $.isFunction(FOOBOX.init)) && FOOBOX.init();
946											func = ($().fancybox) && $('.tg-item a.fancybox').fancybox();
947											func = ($().prettyPhoto) && $('.tg-item  a[rel^="prettyPhoto"]').prettyPhoto();
948											// clean data
949											cleanData($item);
950											return false;
951										}
952										i++;
953									}
954								},options.ajaxDelay);
955							}
956						});
957					},
958					error : function(jqXHR, textStatus, errorThrown) {
959						page = page - 1;
960						console.error(jqXHR);
961						console.error(textStatus + " :: " + errorThrown);
962					}
963				});
964			}
965			
966			// only if in backend mode for preview
967			function get_meta_data(){
968				if ($preview.length > 0) {
969					return new TG_metaData($('#the_grid_metabox .tomb-row'));
970				}
971			}
972			
973			// check hidden item in backend
974			function exclude_item() {
975				if ($preview.length > 0) {
976					TG_excludeItem();
977				}
978			}
979
980		});
981
982	};
983
984	// ======================================================
985	// Custom script (Themeone) : preload img src and/or bg image
986	// ======================================================
987	
988	var tg_img_arr = [];
989	
990	$.fn.the_grid_images_loaded = function() {
991		
992		// current element to search in
993		var el = $(this);
994		
995		// extend the options to complete:
996		var options = $.extend({
997			complete: function() {}
998		}, arguments[0] || {});
999		
1000		// init global var
1001		var count = 0,
1002			preload = [],
1003			img_url;
1004		
1005		// search all image inside current selector
1006		el.find('*').filter(function() {
1007			img_url = $(this).css('background-image');
1008			img_url = /^url\((['"]?)(.*)\1\)$/.exec(img_url);
1009			img_url = img_url ? img_url[2] : null;
1010			img_url = (!img_url && $(this).is('img')) ? $(this).attr('src') : img_url;
1011			img_url = (img_url && (img_url.match(/\.(jpg|jpeg|png|bmp|gif|tif|tiff|jif|jfif)/g)
1012					  || img_url.indexOf('external.xx.fbcdn') >= 0
1013					  || img_url.indexOf('drscdn.500px.org') >= 0)) ? img_url : null;
1014			if (img_url && $.inArray(img_url, tg_img_arr) == -1) {
1015				preload.push(img_url);
1016				tg_img_arr.push(img_url);			
1017			}
1018		});
1019
1020		// load images
1021		var images = [];
1022
1023		for (var i = 0; i < preload.length; i++) {
1024			images[i] = new Image();
1025			images[i].onload  = imgLoaded;
1026			images[i].onerror = imgLoaded;
1027			images[i].onabort = imgLoaded;
1028			images[i].src = preload[i];
1029		}
1030		
1031		// complete if no images
1032		if (!preload.length) {
1033			options.complete.call(el);
1034			return false;
1035		}
1036		
1037		// on load count and compare to array
1038		function imgLoaded() {
1039			count++;
1040			if(count >= preload.length){
1041				options.complete.call(el);
1042				return false;
1043			}
1044		}
1045
1046	};
1047	
1048	// ======================================================
1049	// Custom script (Themeone) : DropDown list (to prevent overflow issue)
1050	// ======================================================
1051		
1052	$(document).ready(function() {
1053
1054		var $filters,
1055			animation    = 'tg-dropdown-holder-animation';
1056			
1057		if (!tg_is_mobile) {
1058		
1059			$(document).on('mouseenter', '.tg-dropdown-holder', function(e) {
1060				e.preventDefault();
1061				e.stopPropagation();
1062				var $this     = $(this),
1063					listTimer = $($this.data('list-DOM')).data('list-timer');
1064				
1065				if (listTimer) {
1066					clearTimeout(listTimer);
1067					$this.data('list-DOM').addClass(animation);
1068					return false;
1069				}
1070	
1071				$filters = $this.find('ul');
1072				
1073				var $list = $filters.clone(true).addClass('tg-list-appended').attr('style','').appendTo('body');
1074				$this.add($list).data('list-DOM', $list);
1075				$list.data('filter-DOM', $this);
1076				
1077				var position = getListPos($this);
1078					
1079				$filters.hide();
1080	
1081				$list.css({
1082					'position'  : 'absolute',
1083					'z-index'   : 99999,
1084					'width'     : position.width,
1085					'top'       : position.top,
1086					'left'      : position.left
1087				}).addClass(animation);
1088				
1089			}).on('mouseleave', '.tg-dropdown-holder', function(e) {
1090				removeList($(this));
1091			});
1092			
1093			$(document).on('mouseenter touchstart', '.tg-list-appended', function(e) {
1094				var $this = $(this);
1095				if ($this.data('list-DOM')) {
1096					clearTimeout($this.data('list-timer'));
1097					$this.data('list-DOM').addClass(animation);
1098					return false;
1099				}
1100			}).on('mouseleave touchend', '.tg-list-appended', function(e) {
1101				removeList($(this));
1102			});	
1103			
1104			$(document).on('click touchstart', '.tg-list-appended li', function(){
1105				
1106				var $this    = $(this).closest('ul'),
1107					$filters = $this.data('filter-DOM');
1108					
1109				$filters.find('[data-filter="'+$(this).data('filter')+'"]').trigger('click');
1110				$filters.find('[data-value="'+$(this).data('value')+'"]').trigger('click');
1111				$this.width($filters.outerWidth());
1112				$this.css('left',$filters.offset().left);
1113				
1114				var position = getListPos($filters);
1115	
1116				if (position.top !== $this.position().top) {
1117					$this.css('top',position.top);
1118				} else {
1119					$this.find('li').removeClass('tg-filter-active');
1120					$filters.find('.tg-filter-active').each(function(i) {
1121						$this.find('li').eq($(this).index()).addClass('tg-filter-active');
1122					});
1123				}
1124	
1125			});
1126
1127		}
1128			
1129		function removeList($this) {
1130			if ($this.data('list-DOM')) {
1131				var $list = $this.data('list-DOM').removeClass(animation);
1132				var timer = setTimeout(function() {
1133					$list.remove();
1134					$list = null;
1135					$this.data('list-DOM', $list);
1136				},400);
1137				$($this.data('list-DOM')).data('list-timer', timer);
1138			}
1139			return false;
1140		}
1141			
1142		function getListPos(el) {	
1143			var offset  = el.parent().offset(),
1144				height  = el.parent().height(),
1145				body    = ($('body').css('position') === 'relative') ?  $(window).scrollTop()+$('body')[0].getBoundingClientRect().top : null,
1146				margin  = parseInt(el.css('margin-bottom')),
1147				width   = el.outerWidth(),
1148				left    = offset.left,
1149				top     = offset.top+height-body-margin;
1150	
1151			var position   = [];
1152			position.top   = top;
1153			position.left  = left;
1154			position.width = width;
1155			return position;
1156		}
1157		
1158	});
1159	
1160	// ======================================================
1161	// Custom script (Themeone) : Tooltip (prevent overflow issue)
1162	// ======================================================
1163		
1164	$.fn.TG_ToolTip = function(options) {
1165		
1166		/*var settings = $.extend({
1167            data        : 'tooltip', // Effect Tooltip class name.
1168			zindex      : 99999,     // z-index css
1169			place       : 'top',     // Default place.
1170			appendClass : 'tooltip', // Class to append
1171			hoverClass  : null,      // Hover class
1172			spacing     : 0          // Gap between target and Tooltip.
1173        }, options);*/
1174		
1175		var toolTip_Data  = 'tooltip-DOM',
1176			toolTip_Timer = 'tooltip-timer';
1177		
1178		$(document).on('mouseenter', $(this).selector, function() {
1179			
1180			var $this = $(this);
1181			
1182			if (!$this.data(options.data)) {
1183				return false;
1184			}
1185
1186			if ($this.data(toolTip_Data)) {
1187				clearTimeout($this.data(toolTip_Timer));
1188				$this.data(toolTip_Data).addClass(options.hoverClass.split('.').join(''));
1189				return false;
1190			}
1191				
1192			var $tooltip = $('<div class="'+options.appendClass.split('.').join('')+'"></div>').appendTo('body');
1193			$this.data(toolTip_Data, $tooltip);
1194
1195			var data   = $this.data(options.data),
1196				offset = $this.offset(),
1197				body    = ($('body').css('position') === 'relative') ? $(window).scrollTop()+$('body')[0].getBoundingClientRect().top : null,
1198				top    = offset.top - body,
1199				left   = offset.left,
1200				width  = $this.outerWidth(true);
1201				
1202			$tooltip.html(data).css({
1203				'position'  : 'absolute',
1204				'z-index'   : options.zindex,
1205				'width'     : width,
1206				'top'       : top+options.spacing-$tooltip.outerHeight(true),
1207				'left'      : left+width/2
1208			}).addClass(options.hoverClass.split('.').join(''));
1209			
1210		}).on('mouseleave', $(this).selector, function() {
1211			
1212			var $this = $(this);
1213			
1214			if (!$this.data(options.data) || !$this.data(toolTip_Data)) {
1215				return false;
1216			}
1217			
1218			var $tooltip = $this.data(toolTip_Data).removeClass(options.hoverClass.split('.').join(''));
1219			var timer    = setTimeout(function() {
1220				$tooltip.remove();
1221				$tooltip = null;
1222				$this.data(toolTip_Data, $tooltip);
1223			},400);
1224			$this.data(toolTip_Timer, timer);
1225			
1226		});
1227		
1228	};
1229	
1230	$(document).ready(function() {
1231		$('.tg-filter-name').TG_ToolTip({
1232			data        : 'tooltip',
1233			zindex      : 99999,
1234			place       : 'top',
1235			appendClass : '.tg-filter-tooltip',
1236			hoverClass  : '.tg-tooltip-hover',
1237			spacing     : -2
1238		});	
1239	});
1240			
1241	// ======================================================
1242	// Handle media content (html-audi/html-video/Youtube/Vimeo/SoundCloud/Wistia) in the grid
1243	// ======================================================
1244	
1245	var tg_media_init = 'tg-media-init',
1246		tg_media_hold = '.tg-item',
1247		ie = (function() { // ie version detection
1248			var v = 3,
1249				div = document.createElement('div'),
1250				all = div.getElementsByTagName('i');
1251			do {div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->';}
1252			while (all[0]);
1253			return v > 4 ? v : document.documentMode; 		
1254		}());
1255
1256	if (ie) {
1257		$('body').addClass('is-ie');
1258	}
1259	
1260	// SoundCloud players (API)
1261	$.fn.TG_SoundCloud = function() {
1262		
1263		return this.each(function () {
1264			
1265			var $this = $(this).closest(tg_media_hold),
1266				src   = $(this).attr('src');
1267			
1268			if (!$this.hasClass(tg_media_init) && src !== 'about:blank') {
1269
1270				var player = SC.Widget($(this).attr('id'));
1271				
1272				player.bind(SC.Widget.Events.READY, function() {
1273				
1274					if ((!player.getCurrentSound && tg_is_mobile) || !tg_is_mobile) {
1275						player.play();
1276					}
1277					
1278					$.TG_Media_Ready($this,player,'STD');
1279				
1280					/*player.bind(SC.Widget.Events.PLAY,function() {
1281						//$.TG_Media_Play($this);
1282					});*/
1283						
1284					player.bind(SC.Widget.Events.PAUSE,function() {
1285						$.TG_Media_Pause($this);
1286					});
1287						
1288					player.bind(SC.Widget.Events.FINISH,function() {
1289						$.TG_Media_Pause($this);
1290					});
1291				
1292				});
1293			
1294			}
1295			
1296		});
1297		
1298	};
1299	
1300	//object to hold all players on the page
1301	var TG_YT_players = {};
1302	// Youtube players (API)
1303	$.fn.TG_Youtube = function() {
1304		
1305		return this.each(function () {
1306	
1307			var $this = $(this).closest(tg_media_hold),
1308				src   = $(this).attr('src');
1309			
1310			if (!$this.hasClass(tg_media_init) && src !== 'about:blank') {
1311	
1312				var playerID = this.id;
1313
1314				TG_YT_players[playerID] = new YT.Player(playerID, {
1315					events: {
1316						'onReady':function(event){
1317							if (!tg_is_mobile) {
1318								event.target.playVideo();
1319							}
1320							$.TG_Media_Ready($this,event.target,'YT'); 
1321						},
1322						'onStateChange': function(event){
1323							if (event.data === 1) {
1324								$.TG_Media_Play($this);
1325							}
1326							if (event.data === 2 ||  event.data === 0) {
1327								$.TG_Media_Pause($this);
1328							}
1329						}
1330					}
1331				});
1332											
1333			}
1334			
1335		});
1336		
1337	};
1338	
1339	// Vimeo players (API)
1340	$.fn.TG_Vimeo = function() {
1341		
1342		return this.each(function () {
1343
1344			var $this = $(this).closest(tg_media_hold),
1345				src   = $(this).attr('src');
1346				
1347			// Vimeo not supported with IE <= 9, so remove iframe & play button
1348			if (ie <= 9) {
1349				$(this).remove();
1350				$this.find('.tg-media-button').remove();
1351			}
1352
1353			if (!$this.hasClass(tg_media_init) && src !== 'about:blank') {
1354				
1355				// reset the src of the iframe because of a cache issue from VIMEO API
1356				$(this).attr('src', $(this).attr('src'));
1357
1358				var player = $f(this);
1359
1360				player.addEvent('ready', function() {
1361					if (!tg_is_mobile) {
1362						player.api('play');
1363					}
1364					$.TG_Media_Ready($this,player,'VM');
1365					player.addEvent('play', function(){
1366						$.TG_Media_Play($this);
1367					});
1368					player.addEvent('pause', function(){
1369						$.TG_Media_Pause($this);
1370					});
1371					player.addEvent('finish', function(){
1372						$.TG_Media_Pause($this);
1373					});
1374				});
1375
1376				/*$(this).attr('src', $(this).attr('src'));
1377				var player = new Vimeo.Player($(this));
1378				
1379				player.play();
1380				$.TG_Media_Ready($this,player,'STD');
1381				player.on('play', function(){
1382					$.TG_Media_Play($this);
1383				});
1384				player.on('pause', function(){
1385					$.TG_Media_Pause($this);
1386				});
1387				player.on('finish', function(){
1388					$.TG_Media_Pause($this);
1389				});*/
1390				
1391			}
1392				
1393		});
1394	};
1395	
1396	// Wistia players (API)
1397	$.fn.TG_Wistia = function() {
1398		
1399		return this.each(function () {
1400	
1401			var $this = $(this).closest(tg_media_hold),
1402				src   = $(this).attr('src');
1403			
1404			if (!$this.hasClass(tg_media_init) && src !== 'about:blank') {
1405				
1406				$(this).load(function() {
1407				
1408					var player = $(this)[0].wistiaApi,
1409						is_init = false,
1410						seeking = false,
1411						heightchange = false;
1412					
1413					
1414					$.TG_Media_Ready($this,player,'STD');
1415					
1416					// prevent issue with Visual Composer on Front-End mode
1417					if (player) {
1418						
1419						player.play();
1420					
1421						player.bind('seek', function () {
1422							seeking = true;
1423						});
1424						
1425						player.bind('heightchange', function () {
1426							heightchange = true;
1427						});
1428						
1429						player.bind('play', function () {
1430							// because of play trigger by seek...
1431							if (seeking === false && heightchange === false && is_init) {
1432								$.TG_Media_Play($this);
1433							}
1434							seeking = heightchange = false;
1435						});
1436		
1437						player.bind('pause', function () {
1438							// because of pause trigger by seek...
1439							if (seeking === false && heightchange === false) {
1440								$.TG_Media_Pause($this);
1441							}
1442							heightchange = is_init = true;
1443						});
1444						
1445						player.bind('finish', function () {
1446							$.TG_Media_Pause($this);
1447						});
1448						
1449					}
1450				
1451				});
1452											
1453			}
1454			
1455		});
1456	};
1457
1458	// HTML5 video/audio players
1459	$.fn.TG_HTML_Player = function() {
1460		
1461		return this.each(function () {
1462			
1463			var $this = $(this).closest(tg_media_hold);
1464			
1465			if (!$this.hasClass(tg_media_init)) {
1466				
1467				var player = $(this)[0];
1468				
1469				if (player.addEventListener) {
1470					$.TG_Media_Ready($this,player,'STD');
1471					player.addEventListener('play', function(){
1472						$.TG_Media_Play($this);
1473					});
1474					player.addEventListener('pause', function(){
1475						$.TG_Media_Pause($this);
1476					});
1477					player.addEventListener('ended', function(){
1478						$.TG_Media_Pause($this);
1479					});
1480				}
1481			}
1482			
1483		});
1484		
1485	};
1486	
1487	// Set player on ready
1488	$.TG_Media_Ready = function(el,player,method) {
1489		el.data('pause-method',method)
1490		  .data('media-player',player)
1491		  .addClass(tg_media_init);  
1492	};
1493	
1494	// handle Play on player
1495	$.TG_Media_Play = function(el) {
1496		if (!el.hasClass('tg-force-play')) {
1497			$.TG_Pause_Players();
1498		}
1499		el.addClass('tg-is-playing');
1500		$(tg_media_hold).removeClass('tg-force-play');
1501	};
1502	
1503	// handle Pause on player
1504	$.TG_Media_Pause = function(el) {
1505		el.removeClass('tg-is-playing tg-force-play');
1506	};
1507	
1508	// detect fullscreen player mode (prevent to add undesired css transform)
1509	$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',function(e){
1510		var el = $(e.target);
1511		$('.tg-item-media').removeClass('tg-item-media-fullscreen');
1512		if (el && el.hasClass('tg-item-media')) {
1513			el.addClass('tg-item-media-fullscreen');
1514		}
1515	});
1516	
1517	// on first play build iframe and init script
1518	$(document).on('click', '.tg-item:not(.tg-media-init) .tg-item-button-play', function(e) {
1519
1520		e.preventDefault();
1521		
1522		var $this     = $(this).closest('.tg-item'),
1523			$media    = $this.find('iframe');
1524
1525		$media.attr('src', $media.data('src'));
1526		$.TG_Pause_Players();
1527		$.TG_media_init();
1528		$this.addClass('tg-force-play');
1529
1530	});
1531	
1532	// Play button
1533	$(document).on('click', '.tg-item.tg-media-init .tg-item-button-play', function(e) {
1534
1535		e.preventDefault();
1536		
1537		var $this  = $(this).closest('.tg-item'),
1538			method = $this.data('pause-method'),
1539			player = $this.data('media-player');
1540
1541		// pause and return if media is playing
1542		if ($this.is('.tg-force-play, .tg-is-playing')){
1543			$.TG_Pause_Players();
1544			return false;
1545		}
1546
1547		// check if player & init, and play
1548		if (player && $this.hasClass(tg_media_init)) {
1549			$this.find('.tg-item-media').show();
1550			$.TG_Pause_Players();
1551			$(tg_media_hold).removeClass('tg-force-play tg-play-error');
1552			$this.addClass('tg-force-play');
1553			switch(method) {
1554				case 'STD':
1555					// prevent auto play SoundCloud on mobile (force manual play to work)
1556					if ((!player.getCurrentSound && tg_is_mobile) || !tg_is_mobile) {
1557						player.play();
1558					}
1559					break;
1560				case 'YT':
1561					player.playVideo();
1562					break;
1563				case 'VM':
1564					player.api('play');
1565					break;
1566			}
1567		}
1568		
1569	});
1570
1571	// Pause all kind of video/audio media
1572	$.TG_Pause_Players = function() {
1573		
1574		$('.tg-item.tg-is-playing, .tg-item.tg-force-play').each(function() {
1575			var $this  = $(this),
1576				method = $this.data('pause-method'),
1577				player = $this.data('media-player');
1578			if (player && $this.hasClass(tg_media_init)) {
1579				switch(method) {
1580					case 'STD':
1581						player.pause();
1582						break;
1583					case 'YT':
1584						player.pauseVideo();
1585						break;
1586					case 'VM':
1587						player.api('pause');
1588						break;
1589				}
1590				$this.closest(tg_media_hold).removeClass('tg-is-playing tg-force-play');
1591			}
1592		});
1593	};
1594
1595	// API scripts (Youtube, Vimeo, Soundclound)
1596	$.TG_media_init = function() {
1597		
1598		var tag,
1599			API,
1600			url,
1601			type,
1602			script,
1603			scripts = [
1604				{'ID':'youtube', 'url':'//www.youtube.com/iframe_api'},
1605				{'ID':'vimeo', 'url':'//f.vimeocdn.com/js/froogaloop2.min.js'},
1606				{'ID':'soundcloud', 'url':'//w.soundcloud.com/player/api.js'},
1607				{'ID':'wistia', 'url':'//fast.wistia.com/assets/external/E-v1.js'}
1608			];
1609		
1610		// load Youtube subscribe button script
1611		if ($('.g-ytsubscribe').length) {
1612			tag = document.createElement('script');
1613			tag.src = 'https://apis.google.com/js/platform.js';
1614			tag.id  = 'tg-youtube-subscribe-api';
1615			script = document.getElementsByTagName('script')[0];
1616			script.parentNode.insertBefore(tag, script);
1617		}
1618		
1619		if ($('.tg-item-media').length === 0) {
1620			return false;
1621		}
1622		
1623		API = {
1624			youtube: function () {
1625				// because of futur ajax events
1626				if (typeof YT == 'undefined' || YT.loaded === 0) {
1627					window.onYouTubeIframeAPIReady = function() {
1628						$('[data-api="1"].tg-item-youtube').TG_Youtube();
1629					};
1630				} else {
1631					$('[data-api="1"].tg-item-youtube').TG_Youtube();
1632				}
1633			},
1634			vimeo: function() {
1635				$('[data-api="1"].tg-item-vimeo').TG_Vimeo();
1636			},
1637			soundcloud: function() {
1638				$('[data-api="1"].tg-item-soundcloud').TG_SoundCloud();
1639			},
1640			wistia: function() {
1641				$('[data-api="1"].tg-item-wistia').TG_Wistia();
1642			}
1643		};
1644		
1645		/* jshint loopfunc:true */
1646		// autoload API scripts (only when necessary)
1647		for (var i = 0; i < scripts.length; i++) {
1648			type = scripts[i].ID;
1649			if ($('[data-api="1"].tg-item-'+type).length > 0) {
1650				url  = scripts[i].url;
1651				if ($('#tg-'+type+'-api').length === 0) {
1652					tag = document.createElement('script');
1653					tag.src = scripts[i].url;
1654					tag.id  = 'tg-'+type+'-api';
1655					script  = document.getElementsByTagName('script')[0];
1656					script.parentNode.insertBefore(tag, script);
1657					(function(tag,type){
1658						tag.onload = function() {
1659							API[type]();
1660						};
1661					})(tag,type);
1662				} else {
1663					API[type]();
1664				}
1665			}
1666		}
1667
1668		// HTML5 Player events
1669		$(document).ready(function() {
1670			$('.tg-item .tg-item-audio-player').attr('width','100%');
1671			$('.tg-item-video-player,.tg-item-audio-player').TG_HTML_Player();
1672			if (tg_global_var.mediaelement) {
1673				$('.tg-item-video-player:not(.tg-mediaelement-init), .tg-item-audio-player:not(.tg-mediaelement-init)').mediaelementplayer({
1674					audioVolume: 'vertical',
1675					videoVolume: 'vertical',
1676					features: ['playpause', 'current', 'progress', 'fullscreen', 'volume', 'duration'],
1677					startVolume: 0.8
1678				});	
1679				$('.tg-item-video-player, .tg-item-audio-player').addClass('tg-mediaelement-init');
1680			}
1681		});
1682
1683	};
1684	
1685	// destroy all video/audio players 
1686	$.TG_media_destroy = function(el) {
1687
1688		var vimeo = (el) ? el : $('.tg-item');
1689		// destroy Vimeo, needed for IE
1690		vimeo.find('.tg-item-vimeo').each(function() {
1691			var $this = $(this),
1692				player = $this.closest(tg_media_hold).data('media-player');
1693			if (player) {
1694				player.api('pause');
1695				$this.attr('src','about:blank');
1696			}
1697		});
1698		
1699		el = (el) ? el.find('.tg-item video, .tg-item audio') : $('.tg-item video, .tg-item audio');
1700		// destroy media player
1701		el.each(function() {
1702						
1703			var $media = $(this),
1704				player = $media.data('mediaelementplayer');
1705				
1706			$media.closest(tg_media_hold).removeClass('tg-force-play tg-is-playing');
1707				
1708			if ($media.length) {
1709				if (player) {
1710					player = $media.data('mediaelementplayer');
1711					player.pause();
1712					player.setSrc('about:blank');
1713					$media.children('source').prop('src', '');
1714					player.remove();
1715				} else {
1716					$media[0].pause();
1717					$media[0].src = 'about:blank';
1718					$media.children('source').prop('src', '');
1719					$media.remove().length = 0;
1720				}
1721			}
1722						
1723		});
1724		
1725		// delete all instances of mediaelement.js
1726		if (tg_global_var.mediaelement) {
1727			mejs.players = [];
1728		}
1729			
1730	};
1731
1732	// ======================================================
1733	// Themeone Lightbox (image/video)
1734	// ======================================================
1735
1736	$.TO_Lightbox = function() {
1737	
1738		var TO_LB_Markup = '<div class="tolb-holder">'+
1739								'<div class="tolb-loader"></div>'+
1740									'<div class="tolb-inner">'+
1741									'<figure>'+
1742										'<div class="tolb-close tg-icon-close"></div>'+
1743										'<div class="tolb-content"></div>'+
1744										'<figcaption>'+
1745											'<div class="tolb-title"></div>'+
1746											'<div class="tolb-counter"></div>'+
1747										'</figcaption>'+
1748									'</figure>'+
1749								'</div>'+
1750								'<div class="tolb-prev"><i class="tg-icon-arrow-prev-thin"></i></div>'+
1751								'<div class="tolb-next"><i class="tg-icon-arrow-next-thin"></i></div>'+
1752							'</div>',
1753			func,
1754			player,
1755			media_id,
1756			media_lb,
1757			media_src,
1758			media_alt,
1759			media_html,
1760			media_type,
1761			media_poster,
1762			media_length,
1763			media_arr  = [],
1764			media_data = '[data-tolb-src]:not(.tolb-disabled)',
1765			holder  = '.tolb-holder',
1766			inner   = '.tolb-inner',
1767			content = '.tolb-content',
1768			video   = '.tolb-video',
1769			image   = '.tolb-img',
1770			title   = '.tolb-title',
1771			counter = '.tolb-counter',
1772			next    = '.tolb-next',
1773			prev    = '.tolb-prev',
1774			close   = '.tolb-close',
1775			index   = 'tolb-index',
1776			open    = 'tolb-open',
1777			ready   = 'tolb-ready',
1778			loading = 'tolb-loading',
1779			iframe  = 'tolb-iframe',
1780			autoplay = tg_global_var.lightbox_autoplay;
1781
1782		function checkLightbox() {
1783			var $media_data = $(media_data).filter(':visible');
1784			media_length = $media_data.length;
1785			for (i = 0; i < media_length; i++) {
1786				var el = $media_data.eq(i);
1787				media_arr[i] = {};
1788				media_arr[i].type   = el.data('tolb-type');
1789				media_arr[i].src    = el.data('tolb-src');
1790				media_arr[i].alt    = el.data('tolb-alt');
1791				media_arr[i].poster = el.data('tolb-poster');
1792				el.data(index,i);
1793			}
1794			if (media_length > 1) {
1795				$(next+','+prev).show();
1796			} else {
1797				$(next+','+prev).hide();
1798			}
1799		}
1800		
1801		function getMedia(el) {
1802			$(holder).addClass(open+' '+loading);
1803			media_id   = el.data(index);
1804			media_type = media_arr[media_id].type;
1805			media_src  = media_arr[media_id].src;
1806			media_alt  = media_arr[media_id].alt;
1807			updateIndex();
1808			switch(media_type) {
1809				case 'image':
1810					media_html = $('<img class="tolb-img" src="'+media_src+'" alt="'+media_alt+'"></img>');
1811					media_lb = new Image();
1812					media_lb.onload  = load_image;
1813					media_lb.onerror = load_image;
1814					media_lb.src = media_src;
1815					break;
1816				case 'youtube':
1817					media_src  = '//www.youtube.com/embed/'+media_src+'?html5=1&controls=1&autohide=1&rel=0&showinfo=0&autoplay='+autoplay;
1818					media_html = $('<iframe class="tolb-video" src="'+media_src+'" allowfullscreen></iframe>');
1819					load_iframe();
1820					break;
1821				case 'vimeo':
1822					media_src  = '//player.vimeo.com/video/'+media_src+'?title=0&amp;byline=0&amp;portrait=0&amp;autoplay='+autoplay;
1823					media_html = $('<iframe class="tolb-video" src="'+media_src+'" allowfullscreen></iframe>');
1824					load_iframe();
1825					break;
1826				case 'wistia':
1827					media_src  = '//fast.wistia.net/embed/iframe/'+media_src+'?title=0&amp;byline=0&amp;portrait=0&amp;autoPlay='+autoplay;
1828					media_html = $('<iframe class="tolb-video" src="'+media_src+'" allowfullscreen></iframe>');
1829					load_iframe();
1830					break;
1831				case 'video':
1832					var source = '';
1833					for(var i=0; i<media_src.length ;i++){
1834						source += '<source src="'+media_src[i][0].source+'" type="video/'+media_src[i][0].type+'" width="100%" height="100%"></source>';
1835					}
1836					media_poster = media_arr[media_id].poster;
1837					media_poster = (media_poster) ? ' poster="'+media_poster+'"' : '';
1838					var attribute = (autoplay) ? ' autoplay' : '';
1839					media_html   = $('<video class="tolb-video" controls'+media_poster+attribute+'>'+source+'</video>');
1840					load_video();
1841					break;
1842			}
1843		}
1844
1845		function unloadMedia() {
1846			var iframe = $(holder).find('iframe').not(media_html);
1847			if (iframe.length > 0) {
1848				iframe.attr('src','about:blank').one('load',function(){
1849					appendMedia();
1850				});
1851			} else {
1852				appendMedia();
1853			}
1854		}
1855		
1856		function appendMedia() {
1857			$(holder).addClass(ready);
1858			func = (media_type !== 'iframe') ?  $(content).html('') : $(content).find('*').not(media_html).remove();
1859			func = (media_type !== 'image') ? $(holder).addClass(iframe) : $(holder).removeClass(iframe);
1860			func = (media_type !== 'iframe') && $(content).append(media_html);
1861			maxHeight();
1862			updateCaption();
1863			media_html.show();
1864			$(holder).removeClass(loading);	
1865		}
1866		
1867		function load_image() {
1868			unloadMedia();
1869		}
1870		
1871		function load_video() {
1872			if (!tg_is_mobile) {
1873				media_html.one('loadeddata',function() {
1874					func = (player) && player.setSrc('about:blank');
1875					if (tg_global_var.mediaelement) {
1876						mediaelement();
1877					} else {
1878						unloadMedia();
1879					}
1880				});
1881				media_html[0].addEventListener('error', function(){
1882					updateCaption();
1883					$(holder).removeClass(loading);
1884				});
1885			} else {
1886				func = (player) && player.setSrc('about:blank');
1887				unloadMedia();
1888			}
1889		}
1890		
1891		function load_iframe() {
1892			media_type = 'iframe';
1893			$(content).append(media_html.hide());
1894			media_html.one('load',function (){
1895				unloadMedia();
1896			});
1897		}
1898		
1899		function mediaelement() {
1900			media_html.mediaelementplayer({
1901				features: ['playpause', 'stop', 'loop', 'current', 'progress', 'duration', 'volume', 'sourcechooser', 'fullscreen'],
1902				videoVolume: 'horizontal',
1903				startVolume: 0.8,
1904				success: function(media, domObject) {
1905					player = media;
1906					media_html = $(domObject).closest('.mejs-container');
1907					unloadMedia();
1908					player.addEventListener('ended', function(){
1909						media_html.find('.mejs-poster').show();
1910					});
1911				}	
1912			});
1913		}
1914		
1915		function maxHeight() {
1916			$(image).css('max-height',$(window).height()-80-$('#wpadminbar').height());
1917		}
1918		
1919		function updateCaption() {
1920			$(title).text(media_alt);
1921			$(counter).text(media_id+1+'/'+media_length);
1922		}
1923		
1924		function updateIndex() {
1925			$(prev).data(index,checkIndex(media_id-1));
1926			$(next).data(index,checkIndex(media_id+1));
1927		}
1928		
1929		function checkIndex(media_id) {
1930			return (media_length + (media_id % media_length)) % media_length;
1931		}
1932		
1933		function close_lightbox() {
1934			$(holder).removeClass(open+' '+loading+' '+ready);
1935			setTimeout(function(){
1936				if ($(holder).find('iframe').length > 0) {
1937					$(holder).find('iframe').attr('src','about:blank').one('load', function(){
1938						$(content).html('');
1939					});
1940				} else {
1941					$(content).html('');
1942				}
1943			}, 300);
1944		}
1945		
1946		$(window).on('resize', function(){
1947			maxHeight();	
1948		});
1949		
1950		$(document).on('click', media_data, function(e) {
1951			e.preventDefault();	
1952			$.TG_Pause_Players();
1953			$(video+','+image).remove();
1954			checkLightbox();
1955			getMedia($(this));
1956			return false;
1957		});
1958	
1959		$(document).on('click touchend',next+','+prev, function() {
1960			getMedia($(this));
1961			return false;
1962		});
1963		
1964		$(document).on('keydown', throttle(function(e) {
1965			if ($(holder).hasClass(open)) {
1966				if (e.keyCode == 37) {
1967					$(prev).trigger('click');
1968				} else if(e.keyCode == 39) {
1969					$(next).trigger('click');
1970				} else if(e.keyCode == 27) {
1971					close_lightbox();
1972				}
1973			}
1974		},300));
1975		
1976		$(document).on('click touchend',inner+','+close, function(e) {
1977			e.stopPropagation();
1978			if ($(e.target).is(inner) || $(e.target).is(close)) {
1979				close_lightbox();
1980			}
1981			return false; 
1982		});
1983		
1984		$('body').append($(TO_LB_Markup));
1985	
1986	};
1987
1988	// auto click lightbox (prevent duplicate content)
1989	$(document).on('click', '[data-tolb-id]', function(e) {
1990		e.preventDefault();
1991		var id = $(this).data('tolb-id');
1992		if (id) {
1993			$('#'+id).trigger('click');
1994		}
1995	});
1996
1997	// ======================================================
1998	// Custom panZoom/Apple TV Effects
1999	// ======================================================
2000	
2001	function TG_PanZoom(){	
2002
2003		var el,offset,h,w,x,y,
2004			edge = window.navigator.userAgent.indexOf('Edge/'),
2005			supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints,
2006			image = 'div:not(.tg-item-gallery-holder) > .tg-item-image, .tg-item-media-poster, .tg-item-audio-poster, .tg-item-gallery-holder',
2007			sensitivity = 0.4,
2008			lastMove = 0;
2009
2010		if (!supportsTouch && !$('body').hasClass('is-ie') && edge < 0) {
2011				
2012			$(document).on('mousemove', '.tg-panZ', function(e){
2013				el = $(this);
2014				w = el.width();
2015				h = el.height();
2016				offset = el.closest('.tg-item').offset();
2017				var now = Date.now();
2018				if (now > lastMove + 80) {
2019					lastMove = now;
2020					window.requestAnimationFrame(function(){
2021						x = -(e.pageX - offset.left-w/2)*0.08*sensitivity;
2022						y = -(e.pageY - offset.top-h/2)*0.08*sensitivity;
2023						$(e.target).closest('.tg-item').find(image).css({
2024							'-webkit-transform': 'matrix(1.08, 0, 0, 1.08,'+x+','+y+')',
2025							'-moz-transform': 'matrix(1.08, 0, 0, 1.08,'+x+','+y+')'
2026						});
2027					});
2028				}
2029			}).on('mouseleave', '.tg-panZ', function(e){
2030				setTimeout(function(){
2031					$(e.target).closest('.tg-item').find(image).css({
2032						'-webkit-transform':'',
2033						'-moz-transform':''
2034					});
2035				}, 80);
2036			});
2037			
2038		}
2039	
2040	}
2041	// Init PanZoom effect
2042	TG_PanZoom();
2043
2044	
2045	// Apple Tv effect
2046	function TG_atv(){
2047	
2048		var d = document,
2049			lastMove = 0,
2050			htm = d.getElementsByTagName('html')[0],
2051			bd  = d.getElementsByTagName('body')[0],
2052			supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints,
2053			eventThrottle = $('body').hasClass('is-ie') ? 1 : 80;
2054		
2055		if (!supportsTouch) {
2056			$(document).on('mousemove', '.tg-atv-anim', function(e){
2057				var holder = $(this),
2058					now = Date.now();
2059				if (now > lastMove + eventThrottle) {
2060					lastMove = now;
2061					window.requestAnimationFrame(function(){
2062						processMovement(e,holder);	
2063					});
2064				}	
2065			}).on('mouseenter', '.tg-atv-anim', function(e){
2066				processEnter($(this));		
2067			}).on('mouseleave', '.tg-atv-anim', function(e){
2068				processExit($(this));	
2069			});
2070		}
2071	
2072		function processMovement(e, layers){
2073			
2074			var bdst  = bd.scrollTop || htm.scrollTop,
2075				bdsl  = bd.scrollLeft,
2076				pageX = e.pageX,
2077				pageY = e.pageY,
2078				offsets = layers[0].getBoundingClientRect(),
2079				w = layers[0].clientWidth || layers[0].offsetWidth || layers[0].scrollWidth,
2080				h = layers[0].clientHeight || layers[0].offsetHeight || layers[0].scrollHeight,
2081				wMultiple = 320/w,
2082				offsetX = 0.52 - (pageX - offsets.left - bdsl)/w,
2083				offsetY = 0.52 - (pageY - offsets.top - bdst)/h,
2084				dy = (pageY - offsets.top - bdst) - h / 2,
2085				dx = (pageX - offsets.left - bdsl) - w / 2,
2086				yRotate = (offsetX - dx)*(0.07 * wMultiple),
2087				xRotate = (dy - offsetY)*(0.1 * wMultiple),
2088				ratio = (h > w) ? h/w*2 : 1,
2089				perspective = w*3*ratio,
2090				imgCSS = 'perspective('+ perspective +'px) rotateX(' + xRotate + 'deg) rotateY(' + yRotate + 'deg) 
2090scale3d(1.03,1.03,1.03)';
2091
2092			layers.css('transform',imgCSS + ' ' + 'translateX(' + (offsetX * 2) * ((1 * 2.5) / wMultiple) + 'px) translateY(' + (offsetY * 1) * ((1 * 2.5) / wMultiple) + 'px)');
2093	
2094		}
2095	
2096		function processEnter(elem){
2097			elem.addClass('over');
2098		}
2099	
2100		function processExit(elem){
2101			elem.removeClass('over');
2102			setTimeout(function(){
2103				var w = elem[0].clientWidth || elem[0].offsetWidth || elem[0].scrollWidth;
2104				elem.css('transform','perspective('+ w*3 +'px) rotateX(0deg) rotateY(0deg) translateZ(0)');
2105			}, 80);
2106		}
2107	
2108	}
2109	// Init Apple TV parallax effect
2110    TG_atv();
2111
2112	// ======================================================
2113	// Social share links
2114	// ======================================================
2115
2116	$(document).on('click', '.tg-social-share:not(.tg-social-disabled)', function(e){
2117		
2118		e.preventDefault();
2119		
2120		var href = $(this)[0].href,
2121			left = Math.round(window.screenX + (window.outerWidth - 626) / 2),
2122			top  = Math.round(window.screenY + (window.outerHeight - 436) / 2);
2123
2124		if (href) {
2125			window.open(href, 'tg_share', 'status=0,resizable=1,location=1,toolbar=0,width=626,height=436,top='+top+',left='+left);
2126		}
2127		
2128		return false;
2129		
2130	});
2131
2132	// ======================================================
2133	// Init The Grid Plugin
2134	// ======================================================
2135	
2136	$.TG_media_init();
2137	// Initializing
2138	$(document).ready(function() {
2139		// because of @keyframe and @font-face issue in Firefox
2140		$('.tg-grid-preloader-styles, .tg-grid-styles').removeAttr('scoped');
2141		$('.tg-grid-holder').The_Grid();
2142		$.TO_Lightbox();	
2143	});
2144
2145
2146	// ======================================================
2147	// Helpers
2148	// ======================================================
2149
2150	// debounced resize
2151	var $event = $.event,
2152		$special,
2153		func,
2154		resizeTimeout;
2155	
2156	$special = $event.special.debouncedresize = {
2157		setup: function() {
2158			$(this).on( "resize", $special.handler );
2159		},
2160		teardown: function() {
2161			$(this).off( "resize", $special.handler );
2162		},
2163		handler: function( event, execAsap ) {
2164			// Save the context
2165			var context = this,
2166				args = arguments,
2167				dispatch = function() {
2168					// set correct event type
2169					event.type = "debouncedresize";
2170					$event.dispatch.apply( context, args );
2171				};
2172	
2173			if ( resizeTimeout ) {
2174				clearTimeout( resizeTimeout );
2175			}
2176	
2177			func = execAsap ? dispatch() : resizeTimeout = setTimeout( dispatch, $special.threshold );
2178		},
2179		threshold: 100
2180	};
2181
2182})(jQuery);
2183
2184// throttle function to reduce calculations
2185function throttle(func, milliseconds) {
2186	var lastCall = 0;
2187	return function () {
2188		var now = Date.now();
2189		if (lastCall + milliseconds < now) {
2190			lastCall = now;
2191			return func.apply(this, arguments);
2192		}
2193	};
2194}
2195
2196// debounce so filtering doesn't happen every millisecond
2197function debounce(fn, threshold) {
2198	
2199	"use strict";
2200	
2201	var timeout;
2202	
2203	return function debounced() {
2204		if (timeout) {
2205			clearTimeout(timeout);
2206		}
2207		function delayed() {
2208			fn();
2209			timeout = null;
2210		}
2211		setTimeout(delayed, threshold || 100);
2212	};
2213}
2214
2215//RAF polyfill (http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/)
2216(function() {
2217    var lastTime = 0;
2218    var vendors = ['webkit', 'moz'];
2219    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
2220        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
2221        window.cancelAnimationFrame =
2222          window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
2223    }
2224
2225    if (!window.requestAnimationFrame)
2226        window.requestAnimationFrame = function(callback, element) {
2227            var currTime = new Date().getTime();
2228            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
2229            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
2230              timeToCall);
2231            lastTime = currTime + timeToCall;
2232            return id;
2233        };
2234
2235    if (!window.cancelAnimationFrame)
2236        window.cancelAnimationFrame = function(id) {
2237            clearTimeout(id);
2238        };
2239}());
2240
2241// RAF interval for smooth animations
2242window.tgInterval = function(a, b) {
2243    var c = Date.now,
2244        d = window.requestAnimationFrame,
2245        e = c(),
2246        f, g = function() {
2247            c() - e < b || (e += b, a());
2248            f || d(g);
2249        };
2250    d(g);
2251    return {
2252        clear: function() {
2253            f = 1;
2254        }
2255    };
2256};
2257
2258/* jshint ignore:start */
2259if (tg_global_var.mediaelement_ex) {
2260// mediaelement extended for loop and source button (The Grid lightbox only)
2261// Loop: http://mediaelementjs.com/examples/?name=loop
2262// source chooser: https://github.com/johndyer/mediaelement/blob/master/src/js/mep-feature-sourcechooser.js	
2263!function(e){e.extend(mejs.MepDefaults,{sourcechooserText:"Source Chooser"}),e.extend(MediaElementPlayer.prototype,{buildsourcechooser:function(o,t,s,c){var r=this;o.sourcechooserButton=e('<div class="mejs-button mejs-sourcechooser-button"><button type="button" aria-controls="'+r.id+'" title="'+r.options.sourcechooserText+'" aria-label="'+r.options.sourcechooserText+'"></button><div class="mejs-sourcechooser-selector"><ul></ul></div></div>').appendTo(t).delegate("input[type=checkbox]","click",function(){var o=this.value;e(this).closest(".mejs-sourcechooser-selector").find("input").removeAttr("checked"),e(this).closest(".mejs-sourcechooser-selector").find("label").removeClass("active"),e(this).next("label").addClass("active"),c.currentSrc!=o&&(currentTime=c.currentTime,paused=c.paused,c.setSrc(o),c.load(),c.addEventListener("loadedmetadata",function(){this.currentTime=currentTime},!0),c.addEventListener("canplay",function(){paused||this.play()},!0))});for(var n in c.children){var i=c.children[n];"SOURCE"!==i.nodeName||"probably"!=c.canPlayType(i.type)&&"maybe"!=c.canPlayType(i.type)||o.addSourceButton(i.src,i.title,i.type,c.src==i.src)}},addSourceButton:function(o,t,s,c){var r=this;(""===t||void 0==t)&&(t=o),s=s.split("/")[1],r.sourcechooserButton.find("ul").append(e('<li><input type="checkbox" name="'+r.id+'_sourcechooser" id="'+r.id+"_sourcechooser_"+s+'" value="'+o+'" '+(c?'checked="checked"':"")+' /><label for="'+r.id+"_sourcechooser_"+s+'">'+s+"</label></li>")),r.adjustSourcechooserBox()},adjustSourcechooserBox:function(){var e=this;e.sourcechooserButton.find(".mejs-sourcechooser-selector").height(e.sourcechooserButton.find(".mejs-sourcechooser-selector ul").outerHeight(!0))}})}(mejs.$),function(e){e.extend(MediaElementPlayer.prototype,{buildloop:function(o,t){var s=this,c=e('<div class="mejs-button mejs-loop-button '+(o.options.loop?"mejs-loop-on":"mejs-loop-off")+'"><button type="button" aria-controls="'+s.id+'" title="Toggle Loop" aria-label="Toggle Loop"></button></div>').appendTo(t).click(function(){o.options.loop=!o.options.loop,o.options.loop?c.removeClass("mejs-loop-off").addClass("mejs-loop-on"):c.removeClass("mejs-loop-on").addClass("mejs-loop-off")})}})}(mejs.$);
2264
2265}
2266/* jshint ignore:end */

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.