PageSourceSearch

https://thenews247.net/wp-content/themes/smart-mag/js/theme.js?ver=10.3.2

js thenews247.net collected 2026-09-24 06:38:47 UTC 53,973 bytes, 2,258 lines download raw bytes

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

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.