PageSourceSearch

https://www.blackhillsballoons.com/wp-content/themes/blackhillsballoons/assets/js/vendor.js?ver=1791433156

js blackhillsballoons.com collected 2026-10-08 04:45:14 UTC 21,037 bytes, 561 lines download raw bytes

1let stickyHeader = () =>{
2    var header = document.querySelector(".mainHeader");
3
4   if (!header) return;
5   let lastScrollTop = 0;
6
7    var sticky = header.offsetTop;
8    var headerHeight = header.offsetHeight;
9
10    document.documentElement.style.setProperty('--headerHeight', headerHeight + "px");
11
12    function checkSticky() {
13         const currentScroll = window.pageYOffset || document.documentElement.scrollTop;
14        if (currentScroll > 100) {
15            header.classList.add("sticky");
16            if (currentScroll > lastScrollTop) {
17                header.classList.add("header-up");
18            }
19            // scrolling up
20            else {
21                header.classList.remove("header-up");
22            }
23        } else {
24            header.classList.remove("sticky");
25            header.classList.remove("header-up");
26        }
27        lastScrollTop = currentScroll <= 0 ? 0 : currentScroll;
28    }
29
30    window.onscroll = function() {
31        checkSticky();
32    };
33    
34}
35
36
37// let stickyHeader = () => {
38//     const header = document.querySelector(".mainHeader");
39    
40
41//     if (!header) return;
42
43//     let lastScrollTop = 0;
44
45//     function handleScroll() {
46//         const currentScroll =
47//             window.pageYOffset || document.documentElement.scrollTop;
48
49//         var headerHeight = header.offsetHeight;
50//         document.documentElement.style.setProperty('--headerHeight', headerHeight + "px");
51
52//         if (currentScroll > 100) {
53//             header.classList.add("sticky");
54
55//             // scrolling down
56//             if (currentScroll > lastScrollTop) {
57//                 header.classList.add("header-up");
58//             }
59//             // scrolling up
60//             else {
61//                 header.classList.remove("header-up");
62//             }
63//         } else {
64//             header.classList.remove("sticky");
65//             header.classList.remove("header-up");
66//         }
67
68//         lastScrollTop = currentScroll <= 0 ? 0 : currentScroll;
69//     }
70
71//     window.addEventListener("scroll", handleScroll);
72// };
73
74
75let itemHeightFix = (item, parent = false)=> {
76    const elements = document.querySelectorAll(item);
77
78    elements.forEach((element) => {
79        const itemHeight = element.offsetHeight;
80        element.style.setProperty("--itemHeight", `${itemHeight}px`);
81        if (parent) {
82            document.querySelector(parent).style.setProperty("--itemHeight", `${itemHeight}px`);
83        }
84    });
85}
86
87
88window.addEventListener('load', () => {
89    stickyHeader();
90    //itemHeightFix('.homeHero .heroOverlay', '.homeHero');
91
92    
93   
94});
95window.addEventListener('resize', () => {
96    stickyHeader();
97   // itemHeightFix('.homeHero .heroOverlay', '.homeHero');
98});
99
100
101document.addEventListener("DOMContentLoaded", function() { 
102
103//itemHeightFix('.homeHero .heroOverlay', '.homeHero');
104
105});
106
107// jQuery(document).ready(function ($) {
108
109// 	function updateAccordionImage(detailsEl) {
110// 		const sourceImg = $(detailsEl).find('.accordionImg img');
111
112// 		if (!sourceImg.length) return;
113
114// 		const src =
115// 			sourceImg.attr('data-src') ||
116// 			sourceImg.attr('data-lazy-src') ||
117// 			sourceImg.attr('src');
118
119// 		const srcset =
120// 			sourceImg.attr('data-srcset') ||
121// 			sourceImg.attr('srcset') ||
122// 			'';
123
124// 		const alt = sourceImg.attr('alt') || '';
125
126// 		const target = $('.accordionRightImage');
127
128// 		if (!target.find('img').length) {
129// 			target.html('<img src="" alt="">');
130// 		}
131
132// 		target.find('img')
133// 			.attr('src', src)
134// 			.attr('srcset', srcset)
135// 			.attr('alt', alt);
136
137// 		// console.log('RIGHT image updated:', src);
138// 	}
139
140// 	/* ✅ On page load */
141// 	const firstOpen = $('details.e-n-accordion-item[open]').first();
142// 	if (firstOpen.length) updateAccordionImage(firstOpen);
143
144// 	/* ✅ Elementor-friendly accordion click */
145// 	$(document).on('click', '.e-n-accordion-item summary', function () {
146
147// 		// Wait for Elementor to update "open" state
148// 		setTimeout(() => {
149// 			const openItem = $(this).closest('.e-n-accordion-item');
150
151// 			if (openItem.attr('open')) {
152// 				updateAccordionImage(openItem[0]);
153// 				// console.log('Accordion clicked & open:', openItem[0]);
154// 			}
155// 		}, 10);
156
157// 	});
158
159// });
160
161jQuery(document).ready(function ($) {
162
163	const rightContainer = $('.accordionRightImage');
164	const accordionItems = $('.e-n-accordion-item');
165	let imagesLoaded = 0;
166	let maxHeight = 0;
167
168	/* ----------------------------
169	   1️⃣ Append images (hidden)
170	----------------------------- */
171	accordionItems.each(function (index) {
172
173		const img = $(this).find('.accordionImg img');
174		if (!img.length) return;
175
176		const src =
177			img.attr('data-src') ||
178			img.attr('data-lazy-src') ||
179			img.attr('src');
180
181		const srcset =
182			img.attr('data-srcset') ||
183			img.attr('srcset') ||
184			'';
185
186		const alt = img.attr('alt') || '';
187
188		const clonedImg = $('<img>', {
189			src,
190			srcset,
191			alt,
192			'data-accordion-index': index,
193			class: 'accordion-right-img'
194		}).css({
195			position: 'relative',
196			visibility: 'hidden',
197			opacity: 0,
198			width: '100%',
199			height: 'auto'
200		});
201
202		clonedImg.on('load', function () {
203			const h = $(this).outerHeight();
204			maxHeight = Math.max(maxHeight, h);
205
206			imagesLoaded++;
207
208			// Once ALL images are measured
209			if (imagesLoaded === accordionItems.length) {
210				rightContainer.css('height', maxHeight + 'px');
211
212				// Switch all images to stacked absolute mode
213				rightContainer.find('.accordion-right-img').css({
214					position: 'absolute',
215					inset: 0,
216					visibility: 'visible'
217				});
218			}
219		});
220
221		rightContainer.append(clonedImg);
222	});
223
224	/* ----------------------------
225	   2️⃣ Show first open accordion
226	----------------------------- */
227	const firstOpen = accordionItems.filter('[open]').first();
228	if (firstOpen.length) {
229		showImage(accordionItems.index(firstOpen));
230	}
231
232	/* ----------------------------
233	   3️⃣ Accordion click handler
234	----------------------------- */
235	$(document).on('click', '.e-n-accordion-item summary', function () {
236		setTimeout(() => {
237			const item = $(this).closest('.e-n-accordion-item');
238			if (!item.attr('open')) return;
239
240			showImage(accordionItems.index(item));
241		}, 10);
242	});
243
244	/* ----------------------------
245	   4️⃣ Image switcher
246	----------------------------- */
247	function showImage(index) {
248		$('.accordion-right-img')
249			.removeClass('is-active')
250			.filter(`[data-accordion-index="${index}"]`)
251			.addClass('is-active');
252	}
253
254}); 
255
256
257document.addEventListener('DOMContentLoaded', function() {
258    const formSelector = '.galleryphotos-fileform';
259    const form = document.querySelector(formSelector);
260    const fileInput = document.querySelector(`${formSelector} .elementor-upload-field`);
261    const uploadFieldContainer = document.querySelector(`${formSelector} .elementor-field-type-upload`);
262
263    if (!form || !fileInput || !uploadFieldContainer) {
264        console.warn('Required form elements not found.');
265        return;
266    }
267
268    // Set multiple attribute if needed
269    fileInput.setAttribute('multiple', 'multiple');
270
271    // 1. Handle file display on selection
272    fileInput.addEventListener('change', function(event) {
273        const files = event.target.files;
274        let fileListDisplay = document.querySelector(`${formSelector} #file-list-display`);
275
276        if (!fileListDisplay) {
277            fileListDisplay = document.createElement('div');
278            fileListDisplay.id = 'file-list-display';
279            uploadFieldContainer.appendChild(fileListDisplay);
280        }
281
282        if (files.length > 0) {
283            fileListDisplay.innerHTML = ''; // Clear previous list
284            for (let i = 0; i < files.length; i++) {
285                const listItem = document.createElement('p');
286                listItem.textContent = files[i].name;
287                fileListDisplay.appendChild(listItem);
288            }
289        } else {
290            fileListDisplay.innerHTML = '<p>No files selected.</p>';
291        }
292    });
293
294    // 2. Clear files on form submission (Elementor Pro event)
295    jQuery(document).on('elementorPro/forms/submit_success', function(event, formId, response) {
296        // Match the specific form using formId (Elementor forms have id="elementor-form-{formId}" or similar)
297        const targetForm = jQuery(`#elementor-form-${formId}, form[data-id="${formId}"]`);
298        if (targetForm.hasClass('galleryphotos-fileform')) {
299            // Clear the file input value
300            jQuery(fileInput).val('');
301
302            // Clear the custom file list display
303            const fileListDisplay = document.querySelector(`${formSelector} #file-list-display`);
304            if (fileListDisplay) {
305                fileListDisplay.innerHTML = '<p>No files selected.</p>';
306            }
307
308            // Force UI refresh for styled upload field (small delay)
309            setTimeout(function() {
310                // Trigger a change event to reset Elementor's label/display if needed
311                fileInput.dispatchEvent(new Event('change', { bubbles: true }));
312                // Optionally, hide/show the container to force repaint (if still stuck)
313                uploadFieldContainer.style.display = 'none';
314                uploadFieldContainer.offsetHeight; // Trigger reflow
315                uploadFieldContainer.style.display = '';
316            }, 100);
317        }
318    });
319
320    // Fallback for non-Pro Elementor or standard submit_success (uncomment if Pro event doesn't work)
321    /*
322    jQuery(document).on('submit_success', function(event, formId, response) {
323        // Same logic as above...
324        const targetForm = jQuery(`#elementor-form-${formId}, form[data-id="${formId}"]`);
325        if (targetForm.hasClass('galleryphotos-fileform')) {
326            // Clear logic here (copy from above)
327        }
328    });
329    */
330
331    // Optional: Handle non-AJAX submission (if form isn't AJAX-enabled)
332    form.addEventListener('submit', function() {
333        // Clear on submit (before send), but this won't catch AJAX success
334        jQuery(fileInput).val('');
335        const fileListDisplay = document.querySelector(`${formSelector} #file-list-display`);
336        if (fileListDisplay) {
337            fileListDisplay.innerHTML = '<p>No files selected.</p>';
338        }
339    });
340});
341
342document.addEventListener('DOMContentLoaded', function() {
343    const parentContainer = document.querySelector('.blogFilter-taxonomy');
344    if (!parentContainer) return;
345
346    const filterContainer = parentContainer.querySelector('.e-filter');
347    if (filterContainer) {
348        // Define the SVG arrow to reuse
349        const arrowSvg = '<span class="droparrow"><svg aria-hidden="true" class="fa-svg-chevron-down e-font-icon-svg e-fas-chevron-down" viewB
349ox="0 0 448 512" xmlns="http://www.w3.org/2000/svg"><path d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"></path></svg></span>';
350
351        // 1. Add extra DIV before the filter (Heading/Label)
352        const titleDiv = document.createElement('div');
353        titleDiv.className = 'filter-header-label';
354        titleDiv.innerHTML = 'Filter By:'; // You can change this text
355        filterContainer.parentNode.insertBefore(titleDiv, filterContainer);
356
357        // 2. Create the Trigger Button
358        const trigger = document.createElement('div');
359        trigger.className = 'filter-dropdown-trigger';
360        
361        // 3. Logic to set default text (Select 'All' or current active)
362        const updateTriggerText = () => {
363            const activeItem = filterContainer.querySelector('.e-filter-item[aria-pressed="true"]');
364            const allItem = filterContainer.querySelector('.e-filter-item'); // Grab the first one (All)
365            
366            let currentText = "Select Filter";
367            if (activeItem) {
368                currentText = activeItem.innerText;
369            } else if (allItem) {
370                currentText = allItem.innerText;
371            }
372            
373            trigger.innerHTML = currentText + ' ' + arrowSvg;
374        };
375
376        // Initial Set
377        updateTriggerText();
378        
379        // Insert trigger after the titleDiv but before filter items
380        filterContainer.parentNode.insertBefore(trigger, filterContainer);
381
382        // 4. Toggle visibility on click
383        trigger.addEventListener('click', function() {
384            filterContainer.classList.toggle('is-open');
385        });
386
387        // 5. Update text when a button is clicked
388        const filterButtons = filterContainer.querySelectorAll('.e-filter-item');
389        filterButtons.forEach(button => {
390            button.addEventListener('click', function() {
391                // Short delay to let Elementor process the click/active state
392                setTimeout(() => {
393                    updateTriggerText();
394                    filterContainer.classList.remove('is-open');
395                }, 50);
396            });
397        });
398
399        // Close dropdown if user clicks outside
400        window.addEventListener('click', function(e) {
401            if (!parentContainer.contains(e.target)) {
402                filterContainer.classList.remove('is-open');
403            }
404        });
405    }
406});
407
408// document.addEventListener('DOMContentLoaded', function() {
409//     // Select the parent container first
410//     const parentContainer = document.querySelector('.blogFilter-taxonomy');
411    
412//     // If the parent doesn't exist on this page, exit the script
413//     if (!parentContainer) return;
414
415//     // Select the filter element within that specific parent
416//     const filterContainer = parentContainer.querySelector('.e-filter');
417    
418//     if (filterContainer) {
419//         // Create the Trigger Button
420//         const trigger = document.createElement('div');
421//         trigger.className = 'filter-dropdown-trigger';
422//         trigger.innerHTML = 'Select Filter <span class="droparrow"><svg aria-hidden="true" class="fa-svg-chevron-down e-font-icon-svg e-fas-chevron-down" viewBox="0 0 448 512" xmlns="http://www.w3.org/2000/svg"><path d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"></path></svg></span>';
423        
424//         // Insert trigger inside the parent, but before the filter items
425//         filterContainer.parentNode.insertBefore(trigger, filterContainer);
426
427//         // Toggle visibility on click
428//         trigger.addEventListener('click', function() {
429//             filterContainer.classList.toggle('is-open');
430//         });
431
432//         // Close dropdown and update text when an item is selected
433//         const filterButtons = filterContainer.querySelectorAll('.e-filter-item');
434//         filterButtons.forEach(button => {
435//             button.addEventListener('click', function() {
436//                 // Update the trigger label to show the active filter
437//                 trigger.innerHTML = this.innerText + ' <span class="droparrow"><svg aria-hidden="true" class="fa-svg-chevron-down e-font-icon-svg e-fas-chevron-down" viewB
437ox="0 0 448 512" xmlns="http://www.w3.org/2000/svg"><path d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"></path></svg></span>';
438//                 filterContainer.classList.remove('is-open');
439//             });
440//         });
441
442//         // Optional: Close dropdown if user clicks outside of the widget
443//         window.addEventListener('click', function(e) {
444//             if (!parentContainer.contains(e.target)) {
445//                 filterContainer.classList.remove('is-open');
446//             }
447//         });
448//     }
449// });
450
451
452document.addEventListener('DOMContentLoaded', function() {
453    // Target the specific video section
454    const videoWrapper = document.querySelector('.video-section');
455    if (!videoWrapper) return;
456
457    const video = videoWrapper.querySelector('video');
458    
459    // The HTML structure you want to re-append
460    const overlayHTML = `
461        <div class="elementor-custom-embed-image-overlay" style="background-image: url(https://blackhillsballoons1.devtest.center/wp-content/uploads/2026/02/experience-video.webp);">
462            <div class="elementor-custom-embed-play" role="button" aria-label="Play Video" tabindex="0">
463                <svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" width="200" height="200" viewBox="0 0 200 200">
464                    <circle cx="100" cy="100" r="95.71" style="opacity: .5;"></circle>
465                    <path d="M100,199.71C45.02,199.71.29,154.98.29,100S45.02.29,100,.29s99.71,44.73,99.71,99.71-44.73,99.71-99.71,99.71ZM100,8.29C49.43,8.29,8.29,49.43,8.29,100s41.14,91.71,91.71,91.71,91.71-41.14,91.71-91.71S150.57,8.29,100,8.29ZM67.81,56.9v85.92c0,3.39,3.67,5.5,6.6,3.81l74.41-42.96c2.93-1.69,2.93-5.93,0-7.62l-74.41-42.96c-2.93-1.69-6.6.42-6.6,3.81Z" style="fill: #fff;"></path>
466                </svg>
467            </div>
468        </div>`;
469
470    // Function to append the overlay
471    const showOverlay = () => {
472        // Check if it already exists to prevent duplicates
473        if (!videoWrapper.querySelector('.elementor-custom-embed-image-overlay')) {
474            video.insertAdjacentHTML('afterend', overlayHTML);
475            
476            // Re-attach click event to the new overlay so clicking it plays the video again
477            const newOverlay = videoWrapper.querySelector('.elementor-custom-embed-image-overlay');
478            newOverlay.addEventListener('click', function() {
479                video.play();
480                newOverlay.remove(); // Remove it immediately when play is clicked
481            });
482        }
483    };
484
485    if (video) {
486        // When video is paused
487        video.addEventListener('pause', function() {
488            showOverlay();
489        });
490
491        // When video ends
492        video.addEventListener('ended', function() {
493            showOverlay();
494        });
495
496        // Remove overlay if video starts playing via other controls
497        video.addEventListener('play', function() {
498            const overlay = videoWrapper.querySelector('.elementor-custom-embed-image-overlay');
499            if (overlay) overlay.remove();
500        });
501    }
502});
503
504document.addEventListener("DOMContentLoaded", function() {
505    const targetNode = document.querySelector('.filter-dropdown-trigger');
506
507    if (targetNode) {
508        // We use a flag to prevent an infinite loop (Observer detects our own changes)
509        let isScriptChanging = false;
510
511        function updateText() {
512            // 1. Get the text node (specifically the first child to avoid the arrow span)
513            let textNode = targetNode.childNodes[0];
514            
515            // Safety check if textNode is missing
516            if (!textNode) return;
517
518            const currentText = textNode.nodeValue;
519            const savedFullText = targetNode.getAttribute('data-full-text');
520
521            if (!savedFullText || (currentText !== savedFullText && !currentText.endsWith('... '))) {
522                 targetNode.setAttribute('data-full-text', currentText.trim());
523            }
524
525            // 3. Perform Truncation Logic
526            const fullText = targetNode.getAttribute('data-full-text');
527            
528            if (window.innerWidth <= 767 && fullText) {
529                const words = fullText.split(/\s+/);
530                if (words.length > 3) {
531                    const truncated = words.slice(0, 3).join(' ') + '... ';
532                    
533                    // Only update if it's not already truncated to avoid loop
534                    if (textNode.nodeValue !== truncated) {
535                        isScriptChanging = true; // Signal that WE are making this change
536                        textNode.nodeValue = truncated;
537                        isScriptChanging = false; // Reset signal
538                    }
539                }
540            } else if (fullText) {
541                // Desktop view: Restore full text
542                 if (textNode.nodeValue.trim() !== fullText) {
543                    isScriptChanging = true;
544                    textNode.nodeValue = fullText + ' ';
545                    isScriptChanging = false;
546                 }
547            }
548        }
549
550        const observer = new MutationObserver(function(mutations) {
551            if (isScriptChanging) return; // Ignore changes made by this script
552            updateText();
553        });
554
555        // Start watching the element for text changes or child list changes
556        observer.observe(targetNode, { childList: true, characterData: true, subtree: true });
557        updateText();
558        // Run on resize
559        window.addEventListener('resize', updateText);
560    }
561});

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.