PageSourceSearch

https://glaad.org/wp-content/themes/smart-mag/js/theme.js?ver=10.5.2

js glaad.org collected 2026-09-27 20:54:11 UTC 54,579 bytes, 2,285 lines download raw bytes

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

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.