PageSourceSearch

https://lasanteauquotidien.com/wp-content/themes/smart-mag/js/theme.js?ver=9.5.0

js lasanteauquotidien.com collected 2026-10-02 18:18:45 UTC 53,834 bytes, 2,256 lines download raw bytes

1/**
2 * SmartMag Theme Frontend JS.
3 * 
4 * @copyright 2023 ThemeSphere.
5 */
6"use strict";
7
8if (!Bunyad) {
9	var Bunyad = {};
10}
11
12Bunyad.theme = (function($) {
13	
14	var hasTouch = false,
15		responsiveMenu = false,
16		isIframe = window.BunyadIsIframe || false,
17		schemeKey = window.BunyadSchemeKey || 'bunyad-scheme';
18		
19	if (!window.requestIdleCallback) {
20		window.requestIdleCallback = requestAnimationFrame;
21	}
22	
23	// module
24	var self = {
25		init: function() {
26
27			// Detect touch capability dynamically.
28			$(window).on('touchstart', function() {
29				// First touch.
30				if (!hasTouch) {
31					$('body').addClass('touch');
32					self.touchNav();
33				}
34
35				hasTouch = true;
36			});
37
38			this.imageEffects();
39			
40			// Setup all sliders
41			this.sliders();
42			this.contentSlideshow();
43			
44			// Setup mobile header and navigation
45			this.header();
46			this.responsiveNav();
47			this.megaMenus();
48			
49			// Start the news ticker
50			this.newsTicker();
51			
52			// Setup the lightbox
53			requestIdleCallback(this.lightbox);
54
55			// Search modal
56			this.searchModal();
57			
58			// Use sticky sidebar if enabled
59			this.initStickySidebar();
60			
61			// User ratings
62			this.userRatings();
63
64			this.tabWidget();
65
66			/**
67			 * Woocommerce
68			 */ 
69			$('.woocommerce-ordering .drop li a').on('click', function(e) {
70				var form = $(this).closest('form');
71				form.find('[name=orderby]').val($(this).parent().data('value'));
72				form.trigger('submit');
73				
74				e.preventDefault();
75			});
76
77			$(document).on('ts-ajax-pagination', e => {
78				$(document).trigger('scroll.TSS');
79				Bunyad.sliders();
80			});
81
82			// Lower priority.
83			requestIdleCallback(() => {
84				self.contextualBinds(document);
85
86				// Nav icons class if missing
87				$('.navigation i.only-icon').each(function() {	
88					var el = $(this).closest('li');
89					if (!el.hasClass('only-icon')) {
90						el.addClass('only-icon');
91					}
92				});
93
94				// Single show comments.
95				$(document).on('click', '.ts-comments-show', function() {
96					$(this).hide()
97						.closest('.comments')
98						.find('.ts-comments-hidden').show();
99					return false;
100				});
101	
102			}, {timeout: 1000});
103		},
104
105		/**
106		 * @param {HTMLDocument|HTMLElement} document
107		 */
108		contextualBinds: function(document)
109		{
110			// Fit videos to container.
111			requestAnimationFrame(() => {
112				$('.featured-vid, .post-content', document).fitVids();
113			});
114
115			// Ratings
116			$('.review-number', document).each(function() {
117				var raw = $(this).find('span:not(.progress)').html(),
118					progress = parseFloat(raw);
119				
120				$(this).find('.progress').css('width', (raw.search('%') === -1 ? (Math.round(progress / 10 * 100)) + '%' : progress));
121			});
122
123			$('.review-box ul li .bar', document).each(function() {
124				$(this).data('width', $(this)[0].style.width).css('width', 0);
125			});
126		
127			new Bunyad_InView(
128				document.querySelectorAll('.review-box ul li', document),
129				entry => {
130					const bar = $(entry.target).find('.bar');
131					bar.addClass('appear').css('width', bar.data('width'));
132				},
133				{once: true}
134			);
135
136			// Single top social sharing view all buttons
137			$('.post-share-b .show-more', document).on('click', function() {
138				$(this).parent().addClass('all');
139				return false;
140			});
141
142			$('.service.s-link').on('click', e => {
143				// Temporary input copy trick as clipboard API only available over https.
144				const temp = document.createElement('input');
145				Object.assign(temp, {
146					value: location.href,
147					style: {position: 'absolute', left: '-200vw'}
148				});
149				document.body.prepend(temp);
150
151				temp.select();
152				document.execCommand('copy');
153				temp.remove();
154
155				let snackbar = document.querySelector('.ts-snackbar.copy-link');
156				if (!snackbar) {
157					snackbar = document.createElement('div');
158
159					const message = e.currentTarget.querySelector('[data-message]').dataset.message;
160					snackbar.className = 'ts-snackbar copy-link';
161					snackbar.innerHTML = `<span>${message}</span><i class="tsi tsi-close"></i>`;
162	
163					document.body.append(snackbar);
164				}
165
166				if (snackbar.classList.contains('ts-snackbar-active')) {
167					return false;
168				}
169
170				requestAnimationFrame(() => snackbar.classList.add('ts-snackbar-active'));
171
172				const hideMessage = () => {
173					snackbar.classList.remove('ts-snackbar-active');
174					snackbar.hide();
175					return false;
176				}
177
178				setTimeout(hideMessage, 5 * 1000);
179				$(snackbar).on('click', '.tsi-close', hideMessage);
180
181				return false;
182			});
183
184			// Go back handler for 404.
185			$('.go-back').on('click', function() { 
186				window.history.back();
187				return false;
188			});
189		},
190
191		/**
192		 * Reinit common theme functionality, in a context, usually ALP feature.
193		 * 
194		 * @param {HTMLDocument|HTMLElement} context
195		 */
196		reInit: function(context) {
197
198			// Only for elements.
199			if (context !== document) {
200				this.imageEffects(context.querySelectorAll('img'));
201			}
202
203			this.contextualBinds(context);
204			this.lightbox();
205			this.contentSlideshow();
206			this.userRatings();
207
208			setTimeout(this.stickySidebar, 50);
209
210			Bunyad.sliders();
211		},
212
213		/**
214		 * Image scroll animations.
215		 */
216		imageEffects: function(elements) {
217
218			// Image effects - remove temp CSS when loaded.
219			if (!$('body').hasClass('img-effects')) {
220				return;
221			}
222
223			if (!elements) {
224				elements = document.querySelectorAll('.main-wrap .wp-post-image, .post-content img');
225			}
226
227			elements.forEach(e => e.classList.add('no-display'));
228			$('.bunyad-img-effects-css').remove();
229
230			new Bunyad_InView(
231				elements,
232				entry => entry.target.classList.add('appear'),
233				{once: true},
234				() => $(elements).addClass('appear')
235			);
236		},
237		
238		newsTicker: function() {
239
240			$('.trending-ticker').each(function() {
241
242				if (!$(this).find('li.active').length) {
243					$(this).find('li:first').addClass('active');
244				}
245				
246				let ticker   = $(this);
247				let interval = false;
248				const delay  = parseInt(ticker.data('delay') || 5) * 1000;
249				
250				const setTick = () => {
251					var active = ticker.find('li.active');
252					active.fadeOut(function() {
253
254						var next = active.next();
255						if (!next.length) {
256							next = ticker.find('li:first');
257						}
258						
259						next.addClass('active').fadeIn();
260						active.removeClass('active');
261					});
262				}
263				
264				const startTicker = () => {
265					if (interval) {
266						return;
267					}
268
269					interval = window.setInterval(setTick, delay);
270				}
271
272				startTicker();
273
274				ticker.on('mouseenter', 'li', () => {
275					clearInterval(interval);
276					interval = false;
277				});
278
279				ticker.on('mouseleave', 'li', startTicker);
280			});
281		},
282		
283		header: function() {
284			
285			const toggleDarkMode = (scheme) => {
286				const prevScheme = (scheme == 'dark' ? 'light' : 'dark');
287
288				// Set initial scheme.
289				const htmlClass = $('html').data('origClass');
290				let initialScheme;
291				if (htmlClass) {
292					initialScheme = htmlClass.includes('s-dark') ? 'dark' : 'light';
293				}
294
295				if ($('html').data('autoDark')) {
296					initialScheme = 'dark';
297				}
298
299				if (scheme !== initialScheme) {
300					localStorage.setItem(schemeKey, scheme);
301				}
302				else {
303					localStorage.removeItem(schemeKey);
304				}
305				
306				$('html')
307					.removeClass(`s-${prevScheme} site-s-${prevScheme}`)
308					.addClass(`s-${scheme} site-s-${scheme}`);
309			};
310			
311			$('.scheme-switcher .toggle').on('click', function() {
312				const ele  = $(this);
313				let scheme = ele.hasClass('toggle-dark') ? 'dark' : 'light';
314
315				toggleDarkMode(scheme);
316
317				// Notify auto-loaded posts.
318				document.querySelectorAll('iframe.spc-auto-load-post').forEach(element => {
319					element.contentWindow.postMessage({
320						action: 'toggle-dark-mode',
321						scheme
322					}, '*');
323				});
324
325				return false;
326			});
327
328			// Listen and change in auto-loaded posts.
329			if (isIframe) {
330				window.addEventListener('message', e => {
331					if (!e.data || e.data.action !== 'toggle-dark-mode') {
332						return;
333					}
334
335					toggleDarkMode(e.data.scheme);
336				});
337			}
338		},
339		
340		/**
341		 * Setup the responsive nav events and markup
342		 */
343		responsiveNav: function() {
344			this.initResponsiveNav();
345		},
346
347		initResponsiveNav: function() {
348			
349			if (responsiveMenu || !$('.off-canvas').length) {
350				responsiveMenu = true;
351				return;
352			}
353			
354			// Set responsive initialized
355			responsiveMenu = true;
356
357			// Test for overlay/non-obstrusive scrollbar (MacOS).
358			const hasOverlayScroll = () => {
359				const ele = document.createElement("div");
360				ele.setAttribute("style", "width:30px;height:30px;overflow:scroll;opacity:0");
361				document.body.appendChild(ele);
362
363				const result = ele.offsetWidth === ele.clientWidth;
364				document.body.removeChild(ele);
365				
366				return result;
367			}
368
369			const setupScroll = () => {
370				if (!hasTouch && !hasOverlayScroll()) {
371					document.body.classList.add("has-scrollbar");
372	
373					// Reflow to fix scrollbars.
374					const ele = $('.off-canvas-content');
375					ele.css('display', 'block');
376	
377					requestAnimationFrame(function() {
378						ele.css('display', 'flex');
379					});
380				}
381			}
382
383			const setupMenuHandlers = () => {
384				// Setup mobile menu click handlers
385				$('.mobile-menu li > a').each(function() {
386					
387					if ($(this).parent().children('ul').length) {
388						$('<span class="chevron"><i class="tsi tsi-chevron-down"></i></span>').insertAfter($(this));
389					}
390				});
391				
392				$('.mobile-menu li .chevron').on('click', function() {
393					$(this).closest('li').find('ul')
394						.first()
395						.parent()
396						.toggleClass('active item-active');
397
398					return false;
399				});
400			}
401
402			const setupMobileMenu = () => {
403				var container = $('.mobile-menu-container');
404
405				// No items for mobile menu? Grab from others
406				if (!container.find('.mobile-menu').children().length) {
407					
408					// Merge existing menus
409					var mobileMenu = container.find('.mobile-menu'),
410						mainMenu = $('.navigation-main .menu');
411						
412					if (!mainMenu.length) {
413						return;
414					}
415
416					var menu = mainMenu.children().clone();
417					
418					// add category mega menu links
419					menu.find('.mega-menu .sub-cats').each(function() {
420						var container = $(this).closest('.menu-item');
421						
422						container.append($(this).find('.sub-nav'));
423						container.find('.sub-nav').replaceWith(function() {
424							return $('<ul />', {html: $(this).html()});
425						});
426						
427						$(this).remove();
428					});
429					
430					mobileMenu.append(menu);
431				}
432			}
433
434			// Delayed setup.
435			let isMenuSetup = false;
436			const initSetup = () => {
437				setupScroll();
438				setupMobileMenu();
439				setupMenuHandlers();
440				
441				isMenuSetup = true;
442			};
443
444			// Bunyad.util.onLoad(() => requestIdleCallback(initSetup, {timeout: 1000}));
445			const showMenu = () => {
446				if (!isMenuSetup) {
447					initSetup();
448				}
449				
450				$('html').toggleClass('off-canvas-active');
451			}
452		
453			$('.mobile-head .menu-icon a, .smart-head .offcanvas-toggle')
454				.on('click', function() {
455					$(document).trigger('ts-sticky-bar-remove');
456					showMenu();
457				});
458
459			// Off-canvas close
460			$('.off-canvas .close').on('click', function() {
461				showMenu();
462				return false;
463			});
464
465			$('.off-canvas-backdrop').on('click', function() {
466				$('.off-canvas .close').click();
467				return false;
468			})
469		},
470
471		megaMenus: function() {
472			const media = window.matchMedia('(min-width: 940px)');
473			const init  = e => {
474				if (e.matches) {
475					this.initMegaMenus();
476				}
477				media.removeListener(init);
478			};
479
480			init(media);
481			media.addListener(init);
482		},
483
484		initMegaMenus: function() {
485			// Bind events for mega menus
486			$('.navigation .mega-menu-a').each(function() {
487				
488				var menu = $(this),
489				    number = menu.find('.recent-posts').data('columns');
490				
491				// Init mega menus
492				var default_mega_menu = function f() {
493					menu.find('.posts').last().addClass('active');
494					return f;
495				}();
496
497				// Mega-menu sub-cats handling.
498				menu.find('.menu-item').on('mouseenter', function() {
499
500					var id = parseInt( $(this).attr('class').match(/menu-cat-(\d+)/)[1] || 0 ),
501					    menu = $(this).parents('.mega-menu'),
502					    view_all = $(this).hasClass('view-all');
503				
504					if (!view_all && !id) {
505						return;
506					}
507					
508					// Remove other actives
509					menu.find('.active, .current-menu-item').removeClass('active current-menu-item');
510
511					// Activate current
512					$(this).addClass('current-menu-item');
513					var posts = menu.find('[data-id=' + id + ']').addClass('active');
514					
515					return false;
516				});
517				
518				// Reset mega menu state on fresh hover
519				menu.parent().on('mouseenter', function() {
520					
521					var menu = $(this).find('.mega-menu');
522					
523					// reset at beginning
524					menu.find('.active, .current-menu-item')
525						.removeClass('active current-menu-item');
526
527					$(this)[0].offsetWidth; // reflow
528					default_mega_menu();
529				});
530				
531			});
532		},
533		
534		/**
535		 * Setup touch navigation for larger touch devices.
536		 */
537		touchNav: function() {
538			
539			var targets = $('.menu:not(.mobile-menu) a'),
540				open_class = 'item-active',
541				child_tag = 'ul, .mega-menu';
542			
543			targets.each(function() {
544				
545				var $this = $(this),
546					$parent = $this.parent('li'),
547					$siblings = $parent.siblings().find('a');
548				
549				$this.on('click', function(e) {
550
551					var $this = $(this);
552					e.stopPropagation();
553					
554					$siblings.parent('li').removeClass(open_class);
555					
556					// has a child? open the menu on tap
557					if (!$this.parent().hasClass(open_class) && $this.next(child_tag).length > 0 && !$this.parents('.mega-menu.links').length) {
558						e.preventDefault();
559						$this.parent().addClass(open_class);
560					}
561				});
562			});
563			
564			// close all menus
565			$(document).on('click', function(e) {
566				if (!$(e.target).is('.menu') && !$(e.target).parents('.menu').length) {
567					targets.parent('li').removeClass(open_class);
568				}
569			});
570		},
571
572		initStickySidebar: function() {
573
574			let hasInit  = false;
575			const events = 'resize orientationchange scroll';
576			const init = () => {
577				if (hasInit) {
578					return;
579				}
580
581				if (document.documentElement.clientWidth >= 940) {
582					self.stickySidebar();
583					hasInit = true;
584					$(window).off(events, init);
585				}
586			}
587
588			$(window).on(events, init);
589			Bunyad.util.onLoad(init);
590		},
591		
592		/**
593		 * Setup sticky sidebar
594		 */
595		stickySidebar: function() {
596
597			const stickyHeaderHeight = () => {
598				const stickyHead = $('.smart-head-sticky');
599				let addHeight = 0;
600				if (stickyHead.length) {
601					let height = window.getComputedStyle(stickyHead[0]).getPropertyValue('--head-h');
602					addHeight = parseInt(height) || 0;
603				}
604
605				return addHeight;
606			}
607
608			const initNative = () => {
609				if (!$('.ts-sticky-native').length) {
610					return;
611				}
612
613				let baseTop = 20;
614				if ($('.admin-bar').length) {
615					baseTop += $('#wpadminbar').height();
616				}
617				
618				const setTop = top => $('body').css('--ts-sticky-top', top + 'px');				
619
620				$(document).on('sticky-bar-show', () => setTop(baseTop + stickyHeaderHeight()));
621				$(document).on('sticky-bar-hide', () => setTop(baseTop));
622			}
623
624			const init = (addExtra) => {
625
626				const sticky = $('.ts-sticky-col, .main-sidebar[data-sticky=1]');
627				if (!sticky.length) {
628					return;
629				}
630				
631				let add = 20;
632				if ($('.admin-bar').length) {
633					add += $('#wpadminbar').height();
634				}
635				add += addExtra || 0;
636
637				sticky.each(function() {
638
639					var stickyCol = $(this);
640					if (stickyCol.data('init') || stickyCol.hasClass('.ts-sticky-native')) {
641						return;
642					}
643
644					stickyCol.data('init', 1);
645					
646					// Add wrapper class if missing
647					if (!stickyCol.find('.theiaStickySidebar').length) {
648						stickyCol.find('.elementor-widget-wrap').first().addClass('theiaStickySidebar');
649						stickyCol.css({display: 'block'});
650					}
651
652					stickyCol.theiaStickySidebar({
653						minWidth: 940, 
654						updateSidebarHeight: false,
655						additionalMarginTop: add,
656						additionalMarginBottom: 20,
657						disableOnResponsiveLayouts: false
658					});
659					
660					// Update TSS internal options on sticky header on / off.
661					const options = stickyCol.data('tss-options');
662
663					if (!options) {
664						return;
665					}
666
667					const stickyInner       = stickyCol.find('.theiaStickySidebar');
668					const stickyColHeight   = stickyCol.outerHeight();
669					const stickyInnerHeight = stickyInner.outerHeight();
670
671					$(document).on('sticky-bar-show', () => {
672						const newMarginTop = add + stickyHeaderHeight();
673
674						// Do nothing if the height will exceed. This would cause a bug at bottom of sticky turning static.
675						if (stickyInnerHeight + newMarginTop >= stickyColHeight) {
676							return;
677						}
678
679						if (newMarginTop !== options.additionalMarginTop) {
680							// Ignore unexpected negative transform of scrolling down.
681							if (!sticky.css('transform').includes('-')) {
682								options.additionalMarginTop = newMarginTop;
683								setTimeout(() => $(window).trigger('scroll.TSS'), 300);
684							}
685						}
686					});
687
688					// Reset margins on sticky bar hide.
689					$(document).on('sticky-bar-hide', () => {
690						options.additionalMarginTop = add;
691						setTimeout(() => $(window).trigger('scroll.TSS'), 300);
692					});
693				});
694			};
695
696			init();
697			initNative();
698			
699			// for iframe loads in sidebar
700			Bunyad.util.onLoad(() => setTimeout(() => {
701				$(window).trigger('resize.TSS');
702			}, 3500));
703		},
704		
705		/**
706		 * Setup legacy slider and slideshow.
707		 */
708		sliders: function() {
709
710			if (!$.fn.flexslider) {
711				return;
712			}
713			
714			var is_rtl = ($('html').attr('dir') == 'rtl' ? true : false);
715			
716			// Classic / Legacy slider.
717			var slider = $('.classic-slider');
718
719			if (!slider.length) {
720				return;
721			}
722			
723			slider.find('.flexslider').flexslider({
724				controlNav: true,
725				animationSpeed: slider.data('animation-speed'),
726				animation: slider.data('animation'),
727				slideshowSpeed: slider.data('slide-delay'),
728				manualControls: '.main-featured .flexslider .pages a',
729				pauseOnHover: true,
730				start: function() {
731					$('.main-featured .slider').css('opacity', 1);
732				},
733				rtl: is_rtl
734			});
735			
736			// Dynamic pagination - if not at default of 5
737			var pages  = slider.find('.pages'),
738				number = parseInt(pages.data('number'));
739			
740			if (number && number !== 5) {
741				var width = (100 - ((number + 1) * 0.284900285)) / number;
741  // 100 - (slides + 1 * margin-left) / slides
742				pages.find('a').css('width', width + '%');
743			}
744		},
745
746		/**
747		 * Post Content Slideshow: AJAX
748		 */
749		contentSlideshow: function() {
750
751			var slideshow_cache = {},
752				slideshow_wrap  = '.post-slideshow .post-pagination-large';
753			
754			if ($(slideshow_wrap).length && !$(slideshow_wrap).data('init') && $(slideshow_wrap).data('type') == 'ajax') {
755			
756				var processing;
757				$(slideshow_wrap).data('init', true);
758
759				$('.main-content').on('click', '.post-slideshow .post-pagination-large .links a', function() {
760					
761						// showing on home-page?
762						if ($('body').hasClass('page')) {
763							return;
764						}
765						
766						// bottom links, scroll top
767						var scroll;
768						if ($(this).parents('.bottom').length) {
769							scroll = true;
770						}
771						
772						// abort existing request
773						if (processing && processing.hasOwnProperty('abort')) {
774							processing.abort();
775						}
776					
777						var parent = $(this).closest('.post-slideshow'),
778							url    = $(this).attr('href');
779						
780						parent.find('.content-page').removeClass('active').addClass('hidden previous');
781					
782						var show_slide = function(data) {
783							
784							// change browser url
785							if (history.pushState) {
786								history.pushState({}, '', url);
787							}
788							
789							var page = $(data).find('.post-slideshow');
790							
791							if (page.length) {
792								parent.find('.post-pagination-large').html(page.find('.post-pagination-large').html());
793								parent.find('.content-page').after(page.find('.content-page').addClass('hidden loading'));
794								
795								setTimeout(function() {
796
797									if (scroll) {
798										$('html, body').animate({scrollTop: parent.offset().top - 50}, 200);
799									}
800									
801									parent.find('.content-page.previous').remove();
802									parent.find('.content-page.loading')
803										.removeClass('previous hidden loading')
804										.find('img').addClass('appear');
805								}, 1);
806							}
807							
808							processing = null;
809							
810						};
811						
812						// in cache?
813						if (slideshow_cache[url]) {
814							show_slide(slideshow_cache[url]);
815						}
816						else {
817							
818							// get via ajax
819							processing = $.get(url, function(data) {
820								slideshow_cache[url] = data;
821								show_slide(data);
822								
823							});
824						}
825						
826						return false;
827				});
828				
829				// keyboard nav
830				$(document).on('keyup', function(e) {				
831						if (e.which == 37) {
832							$(slideshow_wrap).find('.prev').parent().click();
833						}
834						else if (e.which == 39) {
835							$(slideshow_wrap).find('.next').parent().click();
836						}
837				});
838				
839			}
840		},
841				
842		/**
843		 * User Ratings handling
844		 */
845		userRatings: function() {
846			
847			var compute_percent = function(e) {
848				
849				var offset = $(this).offset(),
850				    position, percent;
851				
852				// count from right for RTL
853				if ($('html').attr('dir') == 'rtl')  {
854					offset.left = offset.left + $(this).outerWidth();
855				}
856				
857				position = Math.abs(e.pageX - Math.max(0, offset.left));
858				percent  = Math.min(100, Math.round(position / $(this).width() * 100));
859				
860				return percent;
861			};
862
863			// percent or points?
864			var is_points = true,
865				scale = parseInt($('.review-box .value-title').text()) || 10;
866			
867			if ($('.review-box .overall .percent').length) {
868				is_points = false;
869			}
870			
871			// update the bar and percent/points on hover
872			$('.user-ratings .main-stars, .user-ratings .rating-bar').on('mousemove mouseenter mouseleave', 
873				function(e) {
874				
875					// set main variables
876					var bar = $(this).find('span'),
877						user_ratings = $(this).closest('.user-ratings');
878				
879					bar.css('transition', 'none');
880					
881					if (user_ratings.hasClass('voted')) {
882						return;
883					}
884				
885					// hover over?
886					if (e.type == 'mouseleave') {
887						bar.css('width', bar.data('orig-width'));
888						user_ratings.find('.hover-number').hide();
889						user_ratings.find('.rating').show();
890						return;
891					}
892					
893					var percent = compute_percent.call(this, e);
894					
895					if (!bar.data('orig-width')) {
896						bar.data('orig-width', bar[0].style.width);
897					}
898					
899					bar.css('width', percent + '%');
900					user_ratings.find('.rating').hide();
901					user_ratings.find('.hover-number').show().text((is_points ? +parseFloat(percent / 100 * scale).toFixed(1) : percent + '%'));
902				}
903			);
904			
905			// add the rating
906			$('.user-ratings .main-stars, .user-ratings .rating-bar').on('click', function(e) {
907				
908				// set main variables
909				var bar = $(this).find('span'),
910					user_ratings = $(this).closest('.user-ratings');
911				
912				if (user_ratings.hasClass('voted')) {
913					return;
914				}
915				
916				// setup ajax post data
917				var post_data = {
918						'action': 'bunyad_rate', 
919						'id': user_ratings.data('post-id'), 
920						'rating': compute_percent.call(this, e)
921				};
922				
923				// get current votes
924				var votes = user_ratings.find('.number'),
925					cur_votes = parseInt(votes.text()) || 0;
926				
927				user_ratings.css('opacity', '0.3');
928				bar.data('orig-width', bar[0].style.width);
929				
930				// add to votes and disable further voting 
931				votes.text((cur_votes + 1).toString());
932				
933				$(this).trigger('mouseleave');
934				user_ratings.addClass('voted');
935				
936				$.post(Bunyad.ajaxurl, post_data, function(data) {
937					
938					// update data
939					if (data === Object(data)) {
940
941						// change rating
942						var cur_rating = user_ratings.find('.rating').text();
943						user_ratings.find('.rating').text( cur_rating.search('%') !== -1 ? data.percent + ' %' : data.decimal );
944						
945						bar.css('width', data.percent + '%');
946						bar.data('orig-width', data.percent);
947					}
948					
949					user_ratings.hide().css('opacity', 1).fadeIn('slow');			
950				}, 'json');
951			});
952		},
953		
954		tabWidget: function() {
955			$(document).on('click', '.widget-tabbed .heading a', function() {
956				
957				var tab = $(this).data('tab'),
958					tabs_data = $(this).closest('.widget-tabbed').find('.tabs-data'),
959					parent = $(this).parent().parent(),
960					active = parent.find('.active');
961				
962				if (!active.length) {
963					active = parent.find('li:first-child');
964				}
965
966				active.removeClass('active').addClass('inactive');
967				$(this).parent().addClass('active').removeClass('inactive');
968				
969				// hide current and show the clicked one
970				var active_data = tabs_data.find('.tab-posts.active');
971				if (!active_data.length) {
972					active_data = tabs_data.find('.tab-posts:first-child');
973				}
974				
975				active_data.hide();
976				tabs_data.find('#recent-tab-' + tab).fadeIn().addClass('active').removeClass('inactive');
977
978				return false;
979			});
980		},
981
982		searchModal: function() {
983			let isSetup = false;
984			const target = $('.smart-head .search-icon');
985
986			const setup = () => {
987				if (isSetup || !$.fn.magnificPopup) {
988					return;
989				}
990
991				isSetup = true;
992				const scheme = $('.search-modal-wrap').data('scheme') == 'dark' ? ' s-dark' : '';
993
994				// Search modal
995				target.magnificPopup({
996					items: {
997						src: '.search-modal-wrap',
998						type: 'inline'
999					},
1000					removalDelay: 400,
1001					focus: 'input',
1002					closeBtnInside: false,
1003					closeOnBgClick: false,
1004					mainClass: 'search-modal' + scheme,
1005					midClick: true,
1006					fixedContentPos: true,
1007					autoFocusLast: false
1008				}); 
1009			};
1010
1011			target.on('mouseover', setup);
1012			setTimeout(setup, 400);
1013		},
1014
1015		/**
1016		 * Setup prettyPhoto
1017		 */
1018		lightbox: function() {
1019			
1020			// Can be disabled overall, or on mobile.
1021			if (
1022				!$.fn.magnificPopup 
1023				|| !$('body').hasClass('has-lb') 
1024				|| (!$('body').hasClass('has-lb-sm') && $(window).width() < 768)
1025			) {
1026				return;
1027			}
1028
1029			if (isIframe) {
1030				return;
1031			}
1032			
1033			var mfpInit = {
1034				type: 'image',
1035				tLoading: '',
1036				mainClass: 'mfp-fade mfp-img-mobile',
1037				removalDelay: 300,
1038				callbacks: {
1039					afterClose: function() {
1040						if (this._lastFocusedEl) {
1041							$(this._lastFocusedEl).addClass('blur');
1042						}
1043					}
1044				}
1045			};
1046
1047			/**
1048			 * Filter to handle valid images only.
1049			 */
1050			var filterImages = function() {
1051				
1052				if (!$(this).attr('href')) {
1053					return false;
1054				}
1055				
1056				return $(this).attr('href').match(/\.(jpe?g|webp|png|bmp|gif)($|\?.+?)/); 
1057			};
1058			
1059			/**
1060			 * Handle Galleries in post.
1061			 * 
1062			 * @param {HTMLElement} context
1063			 */
1064			var addGalleryLightbox = function(context) {
1065				var gal_selectors = '.gallery-slider, .post-content .gallery, .post-content .blocks-gallery-item, .post-content .tiled-gallery, .wp-block-gallery .wp-block-image, .tiled-gallery__gallery .tiled-gallery__item';
1066		
1067				// Filter to only tie valid images.
1068				$(gal_selectors, context)
1069					.find('a')
1070					.has('img')
1071					.filter(filterImages)
1072					.addClass('lightbox-gallery-img');
1073
1074				// Add WooCommerce support
1075				$('.woocommerce a[data-rel^="prettyPhoto"], a.zoom').addClass('lightbox-gallery-img');
1076				gal_selectors += ', .woocommerce .images';
1077
1078				// Attach the lightbox as gallery
1079				$(gal_selectors, context).magnificPopup($.extend({}, mfpInit, {
1080					delegate: '.lightbox-gallery-img',
1081					gallery: {enabled: true},
1082					image: {
1083						titleSrc: function(item) {
1084							var image   = item.el.find('img'), 
1085								caption = item.el.find('.caption').html();
1086							
1087							return (caption || image.attr('title') || ' ');
1088						}
1089					}
1090				}));
1091			};
1092			
1093			/**
1094			 * Non-gallery images in posts.
1095			 * 
1096			 * @param {HTMLElement} context 
1097			 */
1098			var addLightboxImages = function(context) {
1099
1100				var selector = 
1101					$('.post-content, .main .featured, .single-creative .featured', context)
1102						.find('a:not(.lightbox-gallery-img)')
1103						.has('img, .img');
1104
1105				selector.add('.lightbox-img')
1106					.filter(filterImages)
1107					.magnificPopup(mfpInit);
1108
1109			};
1110
1111			addGalleryLightbox();
1112			addLightboxImages();
1113
1114			$('iframe.spc-auto-load-post').each(function() {
1115				const iframe = $(this).get(0).contentDocument;
1116				addGalleryLightbox(iframe);
1117				addLightboxImages(iframe);
1118			});
1119			
1120		}
1121	};
1122
1123	self.stickyBarPause = false;
1124
1125	return self;
1126	
1127})(jQuery);
1128/**
1129 * Utility methods.
1130 */
1131Bunyad.util = {
1132	
1133	throttle(fn, delay = 150, trails = true) {
1134
1135		let pause = false;
1136		let trail;
1137		let timeout = function() {
1138			if (trail) {
1139				fn.apply(trail[0], trail[1]);
1140				trail = null;
1141				setTimeout(timeout, delay);
1142			} else {
1143				pause = false;
1144			}
1145		};
1146
1147		return function(...args) {
1148			if (!pause) {
1149				fn.apply(this, args);
1150				pause = true;
1151				setTimeout(timeout, delay);
1152			} else if (trails) {
1153				trail = [this, args];
1154			}
1155		};
1156	},
1157
1158	writeRaf(fn, options) {
1159		var running, 
1160		    args, 
1161		    that;
1162
1163		var run = function() {
1164			running = false;
1165			fn.apply(that, args);
1166		};
1167
1168		if (!options) {
1169			options = {};
1170		}
1171
1172		return function() {
1173			args = arguments;
1174			that = options.that || this;
1175
1176			if (!running) {
1177				running = true;
1178				requestAnimationFrame(run);
1179			}
1180		};
1181	},
1182
1183	onLoad(cb) {
1184		document.readyState === 'complete' ? cb() : window.addEventListener('load', cb);
1185	}
1186};
1187
1188/**
1189 * Authentication modal.
1190 */
1191(function($) {
1192
1193	/** @type {Boolean} */
1194	let isInitialized = false;
1195
1196	function init() {
1197
1198		if (!$('#auth-modal').length) {
1199			return;
1200		}
1201
1202		$(document).on('click', 'a', e => {
1203			if (e.currentTarget.hash === '#auth-modal') {
1204				if (!window.MicroModal) {
1205					return;
1206				}
1207		
1208				initModal();
1209				MicroModal.show('auth-modal', {
1210					awaitCloseAnimation: true
1211				});
1212
1213				e.preventDefault();
1214			}
1215		});
1216	}
1217
1218	function initModal(e) {
1219
1220		if (isInitialized) {
1221			return;
1222		}
1223
1224		const modal  = $('#auth-modal');
1225		const toggle = e => {
1226			modal.find('.auth-modal-login, .auth-modal-register').toggle();
1227			e.preventDefault();
1228		}
1229		
1230		modal.on('click', '.register-link, .login-link', toggle);
1231		isInitialized = true;
1232	}
1233
1234	Bunyad.authModal = init;
1235
1236})(jQuery);
1237(function($) {
1238
1239	const cache = [];
1240
1241	function init() {
1242		$('.section-head .subcats a, .block-head .filters a').on('click', e => {
1243			doFilter(e.currentTarget);
1244			return false;
1245		});
1246	}
1247
1248	function doFilter(ele) {
1249
1250		if ($(this).hasClass('active')) {
1251			return false;
1252		}
1253
1254		ele = $(ele);
1255
1256		const block   = ele.closest('.block-wrap');
1257		const blockId = block.data('id');
1258		const termId  = ele.data('id');
1259		const content = block.find('.block-content');
1260		const curActive = ele.parents('.filters').find('a.active');
1261		
1262		// Store "All" in cache.
1263		if (!curActive.data('id')) {
1264			cache[`${blockId}-0`] = block[0].outerHTML;
1265		}
1266
1267		// Filter links active
1268		ele.addClass('active');
1269		curActive.removeClass('active');
1270
1271		// For pagination.
1272		block.data('filter-active', ele.data('id'));
1273		
1274		const cacheId = `${blockId}-${termId}`;
1275		content.removeClass('fade-in-up-lg')
1276			.addClass('loading');
1277
1278		if (!cache[cacheId]) {
1279
1280			const blockData = block.data('block') || {};
1281			blockData.props.filter = termId;
1282
1283			// AJAX params
1284			const params =  {
1285				action: 'bunyad_block',
1286				block: blockData
1287			};
1288
1289			$.post(
1290				Bunyad.ajaxurl,
1291				params,
1292				data => {
1293					cache[cacheId] = data;
1294					replaceContent(cache[cacheId], block, content);
1295				}
1296			);
1297		}
1298		else {
1299			replaceContent(cache[cacheId], block, content);
1300		}
1301	}
1302
1303	function replaceContent(data, block, content) {
1304		const newHtml    = $(data);
1305		const newContent = newHtml.find('.block-content')
1306		newContent.find('img').addClass('no-display appear');
1307
1308		// Race condition.
1309		newContent.find('.lazyloading').removeClass('lazyloading').addClass('lazyload');
1310		content.removeClass('fade-in-up-lg');
1311
1312		requestAnimationFrame(() => {
1313			content.html(newContent.html())
1314				.removeClass('loading')
1315				.addClass('fade-in-up-lg')
1316				.addClass('ready');
1317		});
1318		
1319		// Set new block data.
1320		block.data('block', newHtml.data('block'));
1321	}
1322
1323	Bunyad.blocksFilters = init;
1324
1325})(jQuery);
1326
1327(function($) {
1328	Bunyad.stickyHeader = function(header, options = {}) {
1329		var nav,
1330			isSmart = false,
1331			isSticky = false,
1332			stickyIsStatic = false,
1333			prevScroll = 0,
1334			curScroll  = 0,
1335			extraTop   = 0,
1336			stickyTop,
1337			hideAt,
1338			head,
1339			headHeight;
1340
1341		let stickyBar;
1342		let stickyIsActive = false;
1343		let hasInitialized = false;
1344		
1345		/**
1346		 * Calculate header size.
1347		 */
1348		const calcHeadSize = Bunyad.util.writeRaf(() => {
1349
1350			// Don't reset if it's stuck
1351			if (stickyIsActive) {
1352				return;
1353			}
1354
1355			var new_height = head.css('min-height', 0).height();
1356			head.css('min-height', new_height);
1357			headHeight = new_height;
1358		});
1359
1360		function setSize(skipCalc) {
1361
1362			// Skip calculation if asked to and head height has been prev set
1363			if (skipCalc && headHeight) {
1364				return;
1365			}
1366
1367			calcHeadSize();
1368		}
1369
1370		/**
1371		 * Remove / disable sticky.
1372		 */
1373		function removeSticky(simpleHide) {
1374		
1375			// Check before dom modification 
1376			if (isSticky) {
1377				
1378				stickyIsActive = false;
1379				let visualHide = false;
1380
1381				// Mainly for smart sticky. Simple hide by not unfixing completely.
1382				if (simpleHide) {
1383					if (!nav.hasClass('off')) {
1384						nav.addClass('off');
1385						visualHide = true;
1386					}
1387				}
1388				else {
1389					// isSticky already checks for presence of smart-head-sticky.
1390					nav.removeClass('smart-head-sticky off');
1391					visualHide = true;
1392				}
1393				
1394				if (visualHide) {
1395					setSize(true);
1396					$(document).trigger('sticky-bar-hide');
1397				}
1398			}
1399		}
1400
1401		/**
1402		 * Make the bar sticky and setup handlers.
1403		 */
1404		function toggleSticky() {
1405
1406			if (stickyIsStatic) {
1407				return;
1408			}
1409
1410			curScroll = $(window).scrollTop();
1411			isSticky  = nav.hasClass('smart-head-sticky');
1412
1413			// Check and apply sticky - separated writes
1414			const stickyWrites = Bunyad.util.writeRaf(() => {
1415				
1416				// Make it sticky when viewport is scrolled beyond the sticky bar.
1417				if (curScroll > stickyTop) {
1418
1419					// For smart sticky, test for scroll change
1420					if (isSmart && (!prevScroll || curScroll > prevScroll)) {
1421						removeSticky(true);
1422					}
1423					else {
1424						stickyIsActive = true;
1425						
1426						if (!isSmart || curScroll < prevScroll-4 && !Bunyad.theme.stickyBarPause) {
1427							if (!nav.hasClass('smart-head-sticky') || nav.hasClass('off')) {
1428								nav.removeClass('off');
1429								nav.addClass('smart-head-sticky');
1430
1431								$(document).trigger('sticky-bar-show');
1432							}
1433						}
1434					}
1435					
1436					prevScroll = curScroll;
1437					
1438				} else {
1439					
1440					// hide at a certain point
1441					if (curScroll <= hideAt) {
1442						prevScroll = 0;
1443						removeSticky();
1444					}
1445				}
1446			});
1447			
1448			stickyWrites();
1449		}
1450
1451		/**
1452		 * Check if smart sticky is enabled.
1453		 */
1454		function checkSmart() {
1455			if (head.data('sticky-type') == 'smart') {
1456				isSmart = true;
1457			}
1458			
1459			if (isSmart && nav.length) {
1460				nav.addClass('is-smart');
1461			}
1462		}
1463
1464		/**
1465		 * Setup calculations and DOM targets.
1466		 */
1467		function setup() {
1468
1469			// Reset vars - might be a re-init
1470			stickyIsStatic = false;
1471			
1472			if ($('.admin-bar').length) {
1473				extraTop = $('#wpadminbar').height();
1474			}
1475
1476			stickyBar = head.data('sticky');
1477			if (!stickyBar) {
1478				return;
1479			}
1480
1481			// Auto detect.
1482			if (stickyBar === 'auto') {
1483				const menu = head.find('.navigation-main .menu');
1484				if (menu.length) {
1485					const match = menu.eq(0).closest('.smart-head-row').attr('class')
1486						.match(/smart-head-(top|mid|bot)/);
1487
1488					if (!match || !match[1]) {
1489						return;
1490					}
1491					
1492					stickyBar = match[1];
1493				}
1494			}
1495		
1496			stickyBar = head.find('.smart-head-' + stickyBar);
1497			nav = stickyBar;
1498
1499			if (!stickyBar.length) {
1500				return;
1501			}
1502
1503			if (head.data('sticky-full')) {
1504				stickyBar.addClass('sticky-is-full');
1505			}
1506			
1507			stickyTop = nav.offset().top - extraTop;
1508			hideAt = stickyTop + 1;
1509
1510			const isLast = head.find('.smart-head-row:last-child').is(stickyBar);
1511			
1512			// If not the last row, show late and hide early to prevent jumps for bottom row.
1513			if (!isLast) {
1514				stickyTop = head.offset().top + head.height();
1515				hideAt = stickyTop + 1;
1516				nav.addClass('animate');
1517			}
1518				
1519			checkSmart();
1520
1521			// For smart, always animate.
1522			if (isSmart) {
1523				nav.addClass('animate');
1524			}
1525
1526			// Android fix on addr bar hide
1527			if (isSmart && !stickyIsActive) {
1528				prevScroll = 0;
1529			}
1530		}
1531
1532		/**
1533		 * Init it - called multiple times to test for init based on width.
1534		 */
1535		function initHandler() {
1536
1537			if (hasInitialized) {
1538				return false;
1539			}
1540	
1541			if (
1542				(options.mobile && $(window).width() > 940)
1543				|| (!options.mobile && $(window).width() <= 940)
1544			) {
1545				return;
1546			}
1547	
1548			setup();
1549			if (!nav || !nav.length) {
1550				return;
1551			}
1552	
1553			// Setup sticky handler 
1554			toggleSticky();
1555	
1556			Bunyad.util.onLoad(calcHeadSize);
1557			$(window).on('scroll', toggleSticky);
1558			
1559			// Re-initialize on resize.
1560			$(window).on('resize orientationchange', () => {
1561				removeSticky();
1562				calcHeadSize();
1563				setup();
1564				toggleSticky();
1565			});
1566
1567			hasInitialized = true;
1568
1569			// Hooks.
1570			$(document).on('ts-sticky-bar-remove', removeSticky);
1571		}
1572
1573		function init(header) {
1574			hasInitialized = false;
1575			head = $(header);
1576
1577			if (!head.length) {
1578				return;
1579			}
1580
1581			initHandler();
1582			$(window).on('resize orientationchange', initHandler);
1583		}
1584
1585		init(header);
1586
1587		return {
1588			init,
1589			getSticky: () => stickyBar,
1590		};
1591	};
1592})(jQuery);
1593/**
1594 * Minimal Element in-viewport handler.
1595 */
1596class Bunyad_InView {
1597	
1598	/**
1599	 * @param {NodeList} elements 
1600	 * @param {CallableFunction} callback 
1601	 * @param {Object} options 
1602	 * @param {CallableFunction} fallback
1603	 */
1604	constructor(elements = [], callback, options = {}, fallback) {
1605
1606		this.elements = elements;
1607		this.callback = callback;
1608		this.options  = Object.assign({
1609			intersectOnly: true,
1610			observeOptions: {},
1611			once: false
1612		}, options);
1613
1614		if (!this.callback) {
1615			return false;
1616		}
1617
1618		if (!window.IntersectionObserver) {
1619			console.warn('Intersection observer missing.');
1620			fallback();
1621			return false;
1622		}
1623
1624		// eslint-disable-next-line compat/compat
1625		this.observer = new IntersectionObserver(
1626			this.handleIntersection.bind(this), 
1627			this.options.observeOptions
1628		);
1629
1630		elements.forEach(element => {
1631			this.observer.observe(element);
1632		});
1633	}
1634
1635	handleIntersection(entries) {
1636
1637		entries.forEach(entry => {
1638			if (this.options.intersectOnly && !entry.isIntersecting) {
1639				return;
1640			}
1641
1642			this.callback.call(this, entry);
1643
1644			if (this.options.once) {
1645				this.observer.unobserve(entry.target);
1646			}
1647		});
1648	}
1649}
1650(function($) {
1651
1652	const cache = [];
1653
1654	/**
1655	 * Setup pagination for blocks.
1656	 */
1657	function init() {
1658
1659		// AJAX pagination handlers
1660		$('.main-wrap')
1661			.on('click', '.main-pagination .load-button, .pagination-numbers[data-type=numbers-ajax] a', e => {
1662				const target = e.currentTarget;
1663
1664				if (target.dataset.processing) {
1665					return;
1666				}
1667
1668				target.dataset.processing = true;
1669
1670				ajaxPagination(target, () => {
1671					target.dataset.processing = false;
1672				});
1673
1674				return false;
1675			});
1676
1677		$('.main-pagination[data-type=infinite]').each(function() {
1678			infiniteLoad($(this).get(0));
1679		});
1680	}
1681
1682	/**
1683	 * Infinite load handler.
1684	 * 
1685	 * @param {Element} pageEle Pagination element container.
1686	 * @param {Object} options 
1687	 */
1688	function infiniteLoad(pageEle, options) {
1689		const block = pageEle.closest('.block-wrap');
1690		pageEle._loads = 1;
1691		options = Object.assign({bottomDeduct: 30}, options);
1692
1693		if (!block) {
1694			return;
1695		}
1696
1697		const offset = {top: 0, bottom: 0};
1698		const compute = () => {
1699			const rect    = block.getBoundingClientRect();
1700			offset.top    = rect.top + window.scrollY;
1701			offset.bottom = offset.top + block.clientHeight - window.innerHeight;
1702
1703			// Page element's height shouldn't be counted + extra deduction.
1704			offset.bottom -= pageEle.clientHeight + options.bottomDeduct;
1705		}
1706
1707		compute();
1708		
1709		let isLoading = false;	
1710		const loadOnScroll = (e) => {
1711
1712			if (isLoading || pageEle._loads > 5) {
1713				return;
1714			}
1715
1716			if (window.scrollY > offset.bottom) {
1717				isLoading = true;
1718				pageEle._loads++;
1719
1720				ajaxPagination(pageEle.querySelector('.load-button'), () => {
1721					compute();
1722					isLoading = false;
1723				});
1724			}
1725		};
1726
1727		$(window).on('scroll', Bunyad.util.throttle(loadOnScroll, 150, false));
1728		$(window).on('resize', Bunyad.util.throttle(compute));
1729	}
1730
1731	function ajaxPagination(ele, callback) {
1732		
1733		ele = $(ele);
1734			
1735		let block    = ele.closest('.block-wrap');
1736		let isBlock = true;
1737		let process  = processLoadMore;
1738		
1739		// Not a block, archives
1740		if (!block.length) {
1741			isBlock = false;
1742			block = ele.closest('.main-content');
1743		}
1744
1745		// AJAX params
1746		const params =  {
1747			action: 'bunyad_block',
1748			block: block.data('block') || {},
1749			paged: (ele.data('page') || 0) + 1
1750		};
1751
1752		// Type of pagination
1753		const type = ele.closest('.main-pagination').data('type');
1754		
1755		switch(type) {
1756		
1757			// Type: Load More
1758			case 'load-more':
1759			case 'infinite':
1760				ele.addClass('loading').find('.tsi').addClass('tsi-spin');
1761				process = processLoadMore;
1762
1763				break;
1764
1765			// Type: Numbered
1766			case 'numbers-ajax':
1767
1768				block.find('.block-content').addClass('loading');
1769				
1770				// Change page number
1771				const permalink = ele.attr('href').match(/\/page\/(\d+)(\/|$)/);
1772				if (permalink !== null) {
1773					params.paged = permalink[1];
1774				}
1775				else {
1776					// Plain links
1777					const src = ele.attr('href').match(/(\?|&)paged?=(\d+)/);
1778					params.paged = src ? src[2] : 1;
1779				}
1780				
1781				// Set height
1782				block.css('height', block.height());
1783				process = processNumbered;
1784
1785				break;
1786		}
1787
1788		// Process block.
1789		if (isBlock) {
1790			
1791			// Home blocks AJAX
1792			const ajaxUrl = Bunyad.ajaxurl;
1793
1794			const blockId = block.data('id');
1795			const cacheId = `${blockId}-${ block.data('filter-active') }-${params.paged}`;
1796
1797			if (!cache[cacheId]) {
1798				$.post(
1799					ajaxUrl,
1800					params,
1801					data => {
1802						requestAnimationFrame(() => {
1803							process(data, block, ele);
1804							cache[cacheId] = data;
1805							!callback || callback();
1806						});
1807					}
1808				);
1809			}
1810			else {
1811				requestAnimationFrame(() => {
1812					process(cache[cacheId], block, ele);
1813					!callback || callback();
1814				});
1815			}
1816		}
1817	}
1818
1819	/**
1820	 * Numbered Ajax callback.
1821	 */
1822	function processNumbered(data, block) {
1823		const blockContent = block.find('.block-content');
1824		
1825		blockContent
1826			.removeClass('fade-in-down-lg')
1827			.html($(data).find('.block-content').html());
1828		
1829		block.css('height', 'auto');
1830		blockContent.addClass('fade-in-down-lg').removeClass('loading');
1831		blockContent.on('animationend', e => blockContent.removeClass('fade-in-down-lg'));
1832
1833		// Scroll to top, temporarily pausing sticky bar.
1834		Bunyad.theme.stickyBarPause = true;
1835		setTimeout(() => { Bunyad.theme.stickyBarPause = false; }, 300);
1836		$('html, body').animate({scrollTop: block.offset().top - 50}, 200);
1837		
1838		$(document).trigger('ts-ajax-pagination');		
1839	}
1840
1841	/**
1842	 * Load More Ajax callback method.
1843	 */
1844	function processLoadMore(data, block, ele) {
1845		
1846		var content = $(data),
1847			posts;
1848		
1849		// Mixed blocks: News Focus, Highlights, Focus Grid.
1850		const isMixed = block.data('is-mixed');
1851		const wrap = isMixed ? block.find('.block-content') : block.find('.loop');
1852		const pagination = block.find('.main-pagination');
1853		
1854		posts = content.find('.loop').children().addClass('fade-in-up-lg');
1855		posts.each(function() {
1856			$(this).on('animationend', () => $(this).removeClass('fade-in-up-lg'));
1857		});
1858
1859		if (isMixed) {
1860			pagination.remove();
1861			wrap.append(content.find('.block-content').children());
1862		}
1863		else {
1864			wrap.append(posts);
1865			
1866			const newPagination = content.find('.main-pagination');
1867			if (newPagination.length) {
1868				pagination.html(newPagination.html());
1869			}
1870			else {
1871				pagination.remove();
1872			}
1873		}
1874
1875		// Masonry reload
1876		if (wrap.hasClass('masonry')) {
1877			// posts.removeClass('fade-in-up-lg');
1878			// Bunyad.theme.masonry(true, posts, wrap.find('.posts-wrap'));
1879		}
1880		
1881		$(document).trigger('ts-ajax-pagination');
1882		
1883		ele.removeClass('loading')
1884			.find('.tsi').removeClass('tsi-spin');
1885	}
1886
1887	Bunyad.pagination = init;
1888})(jQuery);
1889
1890/**
1891 * Live Search Handler
1892 */
1893(function($) {
1894	"use strict";
1895	
1896	var cache = {}, timer, element;
1897	
1898	const self = {
1899		
1900		init: function() {
1901			
1902			var search = $('.live-search-query');
1903
1904			if (!search.length) {
1905				return;
1906			}
1907			
1908			// Turn off browser's own auto-complete
1909			$('.live-search-query').attr('autocomplete', 'off');
1910			
1911			// setup the live search on key press
1912			$('.live-search-query').on('keyup focus', function() {
1913				
1914				element = $(this).parent();
1915			
1916				var query = $(this).val(), result;
1917
1918				// clear existing debounce
1919				clearTimeout(timer);
1920				
1921				// minimum of 1 character
1922				if (query.length < 1) {
1923					self.add_result('');
1924					return;
1925				}
1926				
1927				// debounce to prevent excessive ajax queries
1928				timer = setTimeout(function() {
1929					self.process(query);
1930				}, 250);
1931			});
1932			
1933			// setup hide 
1934			$(document).on('click', function(e) {
1935				
1936				var results = $('.live-search-results');
1937				
1938				if (results.is(':visible') && !$(e.target).closest('.search-form').length) {
1939					results.removeClass('fade-in');
1940					results.closest('form').removeClass('has-live-results');
1941				}
1942			});
1943		},
1944		
1945		/**
1946		 * Process the search query
1947		 */
1948		process: function(query) {
1949
1950			// have it in cache?
1951			if (query in cache) {
1952				self.add_result(cache[query]);
1953			}
1954			else {
1955				$.get(Bunyad.ajaxurl, {action: 'bunyad_live_search', 'query': query}, function(data) {
1956					
1957					// add to cache and add results
1958					cache[query] = data;
1959					self.add_result(data);
1960				});
1961			}
1962		},
1963		
1964		/**
1965		 * Add live results to the container
1966		 */
1967		add_result: function(result) {
1968			
1969			if (!element.find('.live-search-results').length) {
1970				element.append($('<div class="live-search-results"></div>'));
1971			}
1972			
1973			var container = element.find('.live-search-results');
1974
1975			if (!result) {
1976				container.removeClass('fade-in');
1977				return;
1978			}
1979			
1980			// add the html result
1981			container.html(result);
1982			
1983			requestAnimationFrame(function() {
1984				container.addClass('fade-in');
1985				container.closest('form').addClass('has-live-results');
1986			});
1987			
1988		}
1989	};
1990
1991	Bunyad.liveSearch = self.init;
1992	
1993})(jQuery);
1994
1995(function($) {
1996	/**
1997	 * Setup sliders.
1998	 */
1999	function init() {
2000
2001		if (!$.fn.slick) {
2002			return;
2003		}
2004
2005		// Setup all sliders
2006		$('.common-slider .slides:not(.loaded), .loop-carousel:not(.loaded), .gallery-slider:not(.loaded)').each(function() {
2007
2008			const slider = $(this);
2009			if (slider.hasClass('loaded')) {
2010				return;
2011			}
2012
2013			slider.one('init', function() {
2014				$(this).addClass('loaded');
2015			});
2016		
2017			// Common setting
2018			var vars = {
2019				rows: 0,
2020				prevArrow: '<a href="#" class="prev-arrow"><i class="tsi tsi-angle-left"></i></a>',
2021				nextArrow: '<a href="#" class="next-arrow"><i class="tsi tsi-angle-right"></i></a>',
2022				autoplay: slider.data('autoplay') ? true : false,
2023				autoplaySpeed: slider.data('speed') || 5000,
2024				fade: slider.data('animation') == 'fade' ? true : false,
2025				rtl: $('html').prop('dir') === 'rtl'
2026			};
2027				
2028			const sliderType = slider.data('slider');
2029
2030			// First image load.
2031			if (vars.autoplay) {
2032
2033				slider.on('init afterChange', function(e, slick) {				
2034					var ele     = $(this),
2035						current = ele.find('[data-slick-index="' + slick.currentSlide + '"]');
2036
2037					var img = current.find('.wp-post-image').first();
2038					if (!img.length) {
2039						return;
2040					}					
2041
2042					var loaded = img.hasClass('lazyloaded') || (img.is('img:not(.lazyload)') && img.prop('complete'));
2043
2044					if (!loaded) {
2045						img.on('lazyloaded load', function(e) {
2046							slick.slickPlay();
2047						});
2048						
2049						slick.slickPause();
2050					}
2051				});
2052			}
2053			
2054			switch (sliderType) {
2055				case 'feat-grid':
2056					setupFeatGrid(slider, vars);
2057					break;
2058					
2059				case 'carousel':
2060					setupCarousel(slider, vars);
2061					break;
2062
2063				case 'gallery':
2064					setupGallery(slider, vars);
2065					break;
2066			}
2067
2068		});
2069
2070		// Disable anchor jump on arrows
2071		$('.common-slider').on('click', '.slick-arrow', function(e) {
2072			e.preventDefault();
2073		});
2074	}
2075
2076	/**
2077	 * For posts carousels.
2078	 */
2079	function setupCarousel(slider, vars) {
2080
2081		const slidesNum = slider.data('slides') || 1;
2082
2083		// If not defined, use columns - 1, min 2, max 4.
2084		const slidesNumMd = slider.data('slides-md') || (
2085			Math.min(4, Math.max(2, slidesNum - 1))
2086		);
2087
2088		const slidesNumSm = slider.data('slides-sm') || 1;
2089
2090		if (slider.data('arrows')) {
2091			// Set correct top for arrows on init.
2092			slider.on('init', (ele) => {
2093				const height = slider.find('.l-post:first-child .media-ratio').outerHeight();
2094				if (height) {
2095					slider[0].style.setProperty('--arrow-top', (height/2) + 'px');
2096				}
2097			});
2098		}
2099
2100		slider.slick($.extend(vars, {
2101			arrows: slider.data('arrows') ? true : false,
2102			infinite: true,
2103			cssEase: 'ease-out',
2104			speed: 400,
2105			dots: slider.data('dots') ? true : false,
2106			dotsClass: 'nav-dots',
2107			adaptiveHeight: true,
2108			slidesToShow: slidesNum,
2109			slidesToScroll: slidesNum, 
2110			responsive: [
2111				{
2112					breakpoint: 940,
2113					settings: {slidesToShow: slidesNumMd, slidesToScroll: slidesNumMd}
2114				},
2115				{
2116					breakpoint: 540,
2117					settings: {slidesToShow: slidesNumSm, slidesToScroll: slidesNumSm}
2118				}
2119			]
2120		}));
2121	}
2122
2123	/**
2124	 * Setup slider for featured grid.
2125	 */
2126	function setupFeatGrid(slider, vars) {
2127
2128		const scrollNum = slider.data('scroll-num') || 1;
2129		let scrollNumMd = slider.data('scroll-num-md');
2130			
2131		if (!scrollNumMd) {
2132			scrollNumMd = Math.min(2, Math.max(1, scrollNum - 1));
2133		}
2134
2135		slider.slick($.extend(vars, {
2136			arrows: true,
2137			infinite: true,
2138			cssEase: 'ease-out',
2139			speed: 500,
2140			slidesToShow: scrollNum,
2141			slidesToScroll: scrollNumMd, 
2142			responsive: [
2143				{
2144					breakpoint: 940,
2145					settings: {slidesToShow: scrollNumMd, slidesToScroll: scrollNumMd}
2146				},
2147				{
2148					breakpoint: 540,
2149					settings: {slidesToShow: 1, slidesToScroll: 1}
2150				}
2151			]
2152		}));
2153	}
2154
2155	/**
2156	 * Setup gallery slider.
2157	 */
2158	function setupGallery(slider, vars) {
2159			
2160		vars = Object.assign(vars, {
2161			infinite: true,
2162			slidesToShow: 1,
2163			slidesToScroll: 1,
2164			adaptiveHeight: true
2165		});
2166		
2167		const init = () => {
2168			slider.slick(vars);
2169		};
2170
2171		// slider.find('img').eq(0).imagesLoaded(init);
2172		init();
2173	}
2174
2175	Bunyad.sliders = init;
2176})(jQuery);
2177
2178// load when ready
2179jQuery(function($) {
2180		
2181	Bunyad.theme.init();
2182	Bunyad.pagination();
2183	Bunyad.sliders();
2184	Bunyad.blocksFilters();
2185
2186	// Setup sticky headers as applicable.
2187	Bunyad.stickyHeaders = {
2188		main: Bunyad.stickyHeader('.smart-head-main', {mobile: false}),
2189		mobile: Bunyad.stickyHeader('.smart-head-mobile', {mobile: true})
2190	};
2191
2192	Bunyad.liveSearch();
2193	Bunyad.authModal();
2194});
2195/**
2196 * Plugins and 3rd Party Libraries
2197 */
2198
2199/*!
2200* FitVids 1.1
2201* Released under the WTFPL license - http://sam.zoy.org/wtfpl/
2202*/
2203;(function($){$.fn.fitVids=function(options){var settings={customSelector:null,ignore:null};if(!document.getElementById("fit-vids-style")){var head=document.head||document.getElementsByTagName("head")[0];var css=".fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}";var div=document.createElement("div");div.innerHTML='<p>x</p><style id="fit-vids-style">'+css+"</style>";head.appendChild(div.childNodes[1])}if(options){$.extend(settings,options)}return this.each(function(){var selectors=['iframe[src*="player.vimeo.com"]','iframe[src*="youtube.com"]','iframe[src*="youtube-nocookie.com"]','iframe[src*="kickstarter.com"][src*="video.html"]',"object","embed"];if(settings.customSelector){selectors.push(settings.customSelector)}var ignoreList=".fitvidsignore";if(settings.ignore){ignoreList=ignoreList+", "+settings.ignore}var $allVideos=$(this).find(selectors.join(","));$allVideos=$allVideos.not("object object");$allVideos=$allVideos.not(ignoreList);$allVideos.each(function(){var $this=$(this);if($this.parents(ignoreList).length>0){return}if(this.tagName.toLowerCase()==="embed"&&$this.parent("object").length||$this.parent(".fluid-width-video-wrapper").length){return}if((!$this.css("height")&&!$this.css("width"))&&(isNaN($this.attr("height"))||isNaN($this.attr("width")))){$this.attr("height",9);$this.attr("width",16)}var height=(this.tagName.toLowerCase()==="object"||($this.attr("height")&&!isNaN(parseInt($this.attr("height"),10))))?parseInt($this.attr("height"),10):$this.height(),width=!isNaN(parseInt($this.attr("width"),10))?parseInt($this.attr("width"),10):$this.width(),aspectRatio=height/width;if(!$this.attr("id")){var videoID="fitvid"+Math.floor(Math.random()*999999);$this.attr("id",videoID)}$this.wrap('<div class="fluid-width-video-wrapper"></div>').parent(".fluid-width-video-wrapper").css("padding-top",(aspectRatio*100)+"%");$this.removeAttr("height").removeAttr("width")})})}})(window.jQuery||window.Zepto);
2204
2205/**
2206 * Plus/minus polyfill for numbers - used in WooCommerce
2207 * 
2208 * Author Bryce Adams
2209 */
2210jQuery( function( $ ) {
2211
2212	// Quantity buttons
2213	$( 'div.quantity:not(.buttons_added), td.quantity:not(.buttons_added)' )
2214		.addClass( 'buttons_added' )
2215		.append( '<div class="vertical-buttons"><input type="button" value="+" class="plus" /><input type="button" value="-" class="minus" /></div>' );
2216
2217	$( document ).on( 'click', '.plus, .minus', function() {
2218
2219		// Get values
2220		var $qty		= $( this ).closest( '.quantity' ).find( '.qty' ),
2221			currentVal	= parseFloat( $qty.val() ),
2222			max			= parseFloat( $qty.attr( 'max' ) ),
2223			min			= parseFloat( $qty.attr( 'min' ) ),
2224			step		= $qty.attr( 'step' );
2225
2226		// Format values
2227		if ( ! currentVal || currentVal === '' || currentVal === 'NaN' ) currentVal = 0;
2228		if ( max === '' || max === 'NaN' ) max = '';
2229		if ( min === '' || min === 'NaN' ) min = 0;
2230		if ( step === 'any' || step === '' || step === undefined || parseFloat( step ) === 'NaN' ) step = 1;
2231
2232		// Change the value
2233		if ( $( this ).is( '.plus' ) ) {
2234
2235			if ( max && ( max == currentVal || currentVal > max ) ) {
2236				$qty.val( max );
2237			} else {
2238				$qty.val( currentVal + parseFloat( step ) );
2239			}
2240
2241		} else {
2242
2243			if ( min && ( min == currentVal || currentVal < min ) ) {
2244				$qty.val( min );
2245			} else if ( currentVal > 0 ) {
2246				$qty.val( currentVal - parseFloat( step ) );
2247			}
2248
2249		}
2250
2251		// Trigger change event
2252		$qty.trigger( 'change' );
2253
2254	});
2255
2256});

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.