PageSourceSearch

https://yellowdog.ai/wp-content/themes/yellowdog/resources/js/main.js?ver=7.0.5

js yellowdog.ai collected 2026-09-24 09:48:29 UTC 16,965 bytes, 507 lines download raw bytes

1/**
2 * Main JavaScript File
3 *
4 * This file contains the main JavaScript code for the Codehills Kickstarter theme.
5 * It includes jQuery scripts that run when the document is ready and after the page is fully loaded.
6 *
7 * @since 2.0.0
8 * @package WordPress
9 * @subpackage Codehills Kickstarter Theme
10 */
11
12// Theme scripts
13jQuery( document ).ready( function($) {
14    
15    // Filter posts by category
16    $(document).on('change', '.post-filter', function(e) {
17        e.preventDefault();
18        // Get case studie category value
19        var term        = document.getElementById('post-filter').value;
20        var type        = document.getElementById('post-filter').getAttribute('type');
21        var taxonomy    = document.getElementById('post-filter').getAttribute('taxonomy');
22
23        // Load more posts
24        $.ajax({
25            // async: true,
26            url: theme_ajax_params.ajax_url,
27            type: 'post',
28            data: {
29                action          : 'filter_posts',
30                term            : term,
31                type            : type,
32                taxonomy        : taxonomy
33            },
34            success: function(response) {
35                // Convert response to JSON object
36                response = JSON.parse(response);
37
38                // Empty grid
39                $('#posts-grid').empty();
40
41                // Append posts
42                if(response.posts != null) {
43                    $('#posts-grid').append(response.posts);
44                    $('.js-loadmore').remove();
45                }
46            }
47        });
48    });
49
50    var canBeLoaded = true; // this param allows to initiate the AJAX call only if necessary
51    var bottomOffset = 1000; // the distance (in px) from the page bottom when you want to load more posts
52
53    $(window).scroll(function() {
54        var paged       = document.getElementById('paged') ? document.getElementById('paged').value : null;
55        var max_pages   = document.getElementById('max_pages') ? document.getElementById('max_pages').value : null;
56        var type        = document.getElementById('type') ? document.getElementById('type').value : null;
57        var tax         = document.getElementById('tax') ? document.getElementById('tax').value : null;
58
59        // Only proceed if required elements exist
60        if (paged === null || max_pages === null || type === null || tax === null) return;
61
62        // Load more posts
63        if ($(window).scrollTop() > ($(document).height() - $(window).height() - bottomOffset) && canBeLoaded === true) {
64            $.ajax({
65                url: theme_ajax_params.ajax_url,
66                type: 'post',
67                data: {
68                    action: 'loadmore',
69                    paged: paged,
70                    max_pages: max_pages,
71                    type: type,
72                    tax: tax
73                },
74                beforeSend: function(xhr) {
75                    $('.js-loadmore').text('Loading...'); // change the button text, you can also add a preloader image
76                    canBeLoaded = false;
77                },
78                success: function(response) {
79                    // Convert response to JSON object
80                    try {
81                        response = JSON.parse(response);
82                    } catch (e) {
83                        canBeLoaded = true;
84                        $('.js-loadmore').text('More Post');
85                        return;
86                    }
87
88                    // Append posts
89                    if (response.posts != null) {
90                        $('#posts-grid').append(response.posts);
91                        $('.js-loadmore').text('More Post');
92                        canBeLoaded = true; // the ajax is completed, now we can run it again
93                        $('#paged').val(response.page); // update the paged value
94                    }
95                    if (response.no_more_posts === true) {
96                        $('.js-loadmore').remove();
97                    }
98                }
99            });
100        }
101    });
102
103});
104
105// Theme scripts after the page is loaded
106jQuery( window ).on( 'load', function() {
107    // Remove 'body' style attribute when the page is loaded
108    $( 'body' ).removeAttr( 'style' );
109
110    // Initialize Splide Logo slider
111    var splide_logos = document.getElementsByClassName('splide-logos');
112        
113    for ( var i = 0; i < splide_logos.length; i++ ) {
114        var splide = new Splide( splide_logos[ i ], {
115            type        : 'loop',
116            drag        : 'free',
117            perPage     : 7,
118            pagination  : false,
119            arrows      : false,
120            gap         : '3rem',
121            autoWidth   : true,
122            // autoplay    : true,
123            autoScroll  : {
124                speed   : 0.5,
125                pauseOnHover : false
126            },
127            breakpoints: {
128                979     : {
129                    perPage: 5,
130                },
131                639     : {
132                    perPage: 3,
133                    gap    : '1.5rem',
134                    autoWidth : false,
135                },
136            },
137        });
138        
139        splide.mount(window.splide.Extensions);
140    }
141
142    // Initialize Splide Journey slider
143    var splide_journey = document.getElementsByClassName('splide-journey').length;
144    
145    if(splide_journey) {
146        var splide = new Splide( '.splide-journey', {
147            type        : 'loop',
148            drag        : 'free',
149            perPage     : 3,
150            gap         : '120px',
151            pagination  : false,
152            speed       : 1600,
153            breakpoints: {
154                1399     : {
155                    gap    : '3rem',
156                    perPage: 3,  
157                    padding: '5rem',
158                },
159                1119     : {
160                    perPage: 2,  
161                    padding: '5rem',
162                },
163                639     : {
164                    perPage: 1,  
165                    padding: '2rem',
166                },
167                439     : {
168                    padding: '0rem',
169                },
170            },
171        });
172        
173        splide.mount();
174    }
175
176    // Initialize Splide Journey slider
177    var splide_case_studies = document.getElementsByClassName('splide-case-studies').length;
178    
179    if(splide_case_studies) {
180        var splide = new Splide( '.splide-case-studies', {
181            type        : 'loop',
182            drag        : 'free',
183            perPage     : 3,
184            gap         : '24px',
185            pagination  : false,
186            speed       : 1000,
187            perMove: 1,
188            padding: { left: '16rem' },
189            autoScroll  : {
190                speed   : 0.5
191            },
192            breakpoints: {
193                1399     : {
194                    perPage: 2,  
195                    padding: '6rem',
196                },
197                979     : {
198                    padding: '2rem',
199                },
200                639     : {
201                    perPage: 1,  
202                    padding: '1.5rem',
203                },
204            },
205        });
206        
207        splide.mount(window.splide.Extensions);
208    }
209
210    gsap.registerPlugin(ScrollTrigger);
211    // Animated content with gsap (opacity to full color)
212    document.querySelectorAll('.animated-content').forEach((splitElement) => {
213        let text = new SplitType(splitElement, {
214            types: 'words, chars'
215        });
216      
217        gsap.fromTo(text.chars, 
218            { opacity: 0.1 }, 
219            { 
220                opacity: 1,
221                stagger: 0.05,
222                scrollTrigger: {
223                    trigger: splitElement,
224                    start: 'top center',
225                    end: 'bottom center',
226                    scrub: 1,
227                    pinType: "transform", // iOS fix
228                }
229            }
230        )
231    });
232    setTimeout(() => {
233        ScrollTrigger.refresh(); // re-calculates trigger positions;
234    }, 500);
235});
236
237// Theme scripts after the DOM is fully loaded
238document.addEventListener('DOMContentLoaded', () => {
239
240    // Header active class on scroll
241    var header = document.querySelector('header');
242  
243    window.addEventListener('scroll', () => {
244        
245        // Sticky cards function
246        // Call stickyCards function to adjust card positions
247        stickyCards();
248
249        if (!header) return;
250
251        // Toggle header classes
252        if (window.scrollY > 0) {
253            header.classList.add('header-active');
254        } else {
255            header.classList.remove('header-active');
256        }
257
258        // Change header class based on section data-color
259        // Find all sections with data-color attribute
260        var sections = document.querySelectorAll('section[data-color]');
261        var found = false;
262
263        // Loop through sections to find the one in viewport
264        sections.forEach(section => {
265            var rect = section.getBoundingClientRect();
266            // Check if section is in viewport (top <= 80px && bottom > 80px)
267            if (!found && rect.top <= 80 && rect.bottom > 80) {
268                var color = section.getAttribute('data-color');
269                if (color === 'light') {
270                    header.classList.add('header-light');
271                    header.classList.remove('header-dark');
272                } else {
273                    header.classList.add('header-dark');
274                    header.classList.remove('header-light');
275                }
276                found = true;
277            }
278        });
279        // If no section is found in viewport, remove both classes
280        if (!found) {
281            header.classList.remove('header-light');
282            header.classList.remove('header-dark');
283        }
284
285        lastScrollY = window.scrollY;
286    });
287
288    // Media block image animation on scroll
289    var elements = document.querySelectorAll('.media-block-image');
290
291    if (elements.length > 0) {
292        var initial = {
293            translateY: 14.6289,
294            scale: 0.90857,
295            rotateX: 6.09536,
296            opacity: 0.817139
297        };
298
299        var final = {
300            scale: 1,
301            opacity: 1
302        };
303
304        // Define scroll range
305        var startScroll = 100;
306        var endScroll = 300;
307
308        function animateAll() {
309            var scrollY = window.scrollY;
310            var progress = Math.min(Math.max((scrollY - startScroll) / (endScroll - startScroll), 0), 1);
311
312            elements.forEach(function(element) {
313                // Interpolate each property
314                var translateY = initial.translateY * (1 - progress);
315                var scale = initial.scale + (final.scale - initial.scale) * progress;
316                var rotateX = initial.rotateX * (1 - progress);
317
318                // Apply styles
319                element.style.transform = `perspective(1200px) translateY(${translateY}px) scale(${scale}) rotateX(${rotateX}deg)`;
320            });
321
322            requestAnimationFrame(animateAll);
323        }
324
325        requestAnimationFrame(animateAll);
326    }
327
328    // Interactive bubble animation on mouse move
329    var inter_bubble = document.querySelector('.interactive');
330
331    if (typeof(inter_bubble) != 'undefined' && inter_bubble != null) {
332        var curX = 0;
333        var curY = 0;
334        var tgX  = 0;
335        var tgY  = 0;
336
337        function move() {
338            curX += (tgX - curX) / 20;
339            curY += (tgY - curY) / 20;
340            inter_bubble.style.transform = `translate(${Math.round(curX)}px, ${Math.round(curY)}px)`;
341            requestAnimationFrame(() => {
342                move();
343            });
344        }
345
346        window.addEventListener('mousemove', (event) => {
347            tgX = event.clientX;
348            tgY = event.clientY;
349        });
350
351        move();
352    }
353
354    // // Add wrapper around iframes in article content
355    // var iframes = document.querySelectorAll('iframe');
356
357    // iframes.forEach(iframe => {
358    //     if (document.querySelector('.article-content')) {
359    //         var wrapper = document.createElement('div');
360    //         wrapper.classList.add('iframe-wrapper');
361
362    //         // Insert the wrapper before the iframe
363    //         iframe.parentNode.insertBefore(wrapper, iframe);
364
365    //         // Move the iframe into the wrapper
366    //         wrapper.appendChild(iframe);
367    //     }
368    // });
369
370    const article = document.querySelector('.article-content');
371    if (!article) return;
372
373    const iframes = article.querySelectorAll('iframe');
374
375    iframes.forEach(iframe => {
376        // Skip hidden / tracking iframes
377        if (
378            iframe.width === '0' ||
379            iframe.height === '0' ||
380            iframe.style.display === 'none' ||
381            iframe.style.visibility === 'hidden' ||
382            iframe.closest('.iframe-wrapper')
383        ) {
384            return;
385        }
386
387        const wrapper = document.createElement('div');
388        wrapper.className = 'iframe-wrapper';
389
390        iframe.parentNode.insertBefore(wrapper, iframe);
391        wrapper.appendChild(iframe);
392    });
393
394    
395});
396
397// Lottie Interactivity
398var players = document.querySelectorAll('.lottie');
399
400players.forEach(player => {
401    player.addEventListener('ready', function() {
402        LottieInteractivity.create({
403            player: player.getLottie(),
404            mode: "scroll",
405            actions: [
406                {
407                    visibility:[0.2, 1],
408                    type: "playOnce"
409                }
410            ]
411        });
412    });
413});
414
415// Sticky cards function
416function stickyCards() {
417    var cards = document.querySelectorAll('.card');
418    var is_tablet = window.innerWidth <= 959;
419    var is_mobile = window.innerWidth <= 639;
420    var is_tablet_height = window.innerHeight <= 849;
421
422    if (cards.length === 0) return; // Exit if no cards are found
423
424    cards.forEach((card, index) => {
425        var nextCard = cards[index + 1];
426        if (!nextCard) return; // Skip the last card
427
428        var cardRect = card.getBoundingClientRect();
429        var nextCardRect = nextCard.getBoundingClientRect();
430
431        var overlap = Math.max(0, cardRect.bottom - nextCardRect.top);
432        var progress = overlap / cardRect.height;
433
434        // Clamp progress between 0 and 1
435        progress = Math.min(Math.max(progress, 0), 1);
436
437        card.style.transform = `scale(${1 - 0.2 * progress})`;
438        card.style.opacity = `${1 - progress}`;
439        if (is_mobile) {
440            var card_height = card.offsetHeight + 200;
441
442            // Use half the height, even if negative (for tall cards)
443            card.style.position = 'sticky';
444            card.style.top = `${(-card_height) / 2}px`;
445        } else if (is_tablet) {
446            // Tablet fallback
447            card.style.position = 'sticky';
448            card.style.top = '-300px'; 
449        } else if (is_tablet_height) {
450            // Desktop fallback
451            card.style.position = 'sticky';
452            card.style.top = '-100px';
453        } else {
454            // Desktop fallback
455            card.style.position = 'sticky';
456            card.style.top = '60px';
457        }
458    });
459}
460
461// Update combined section height for CSS variable
462function updateCombinedHeight() {
463    var sections = document.querySelectorAll('.section-height');
464    var totalHeight = 0;
465
466    sections.forEach(section => {
467        totalHeight += section.offsetHeight;
468    });
469
470    // Check last section and add half height only if it has `.add-half`
471    if (sections.length > 0) {
472        var lastSection = sections[sections.length - 1];
473
474        if (lastSection.classList.contains('section-height-half')) {
475            var halfHeight = lastSection.offsetHeight / 2;
476            totalHeight -= halfHeight;
477        }
478    } // Set CSS variable
479    document.documentElement.style.setProperty('--combined-section-height', `${totalHeight}px`);
480}
481
482// Initial call to set combined height
483window.addEventListener('load', () => {
484    setTimeout(updateCombinedHeight, 200);
485});
486
487// Run on resize (for mobile rotation)
488window.addEventListener('resize', () => {
489    stickyCards();
490    updateCombinedHeight();
491});
492
493// YouTube video play on click
494document.querySelectorAll('.youtube-video').forEach((video) => {
495
496    const button = video.querySelector('.youtube-trigger');
497    const iframe = video.querySelector('.youtube-iframe');
498
499    button.addEventListener('click', () => {
500
501        iframe.src = iframe.dataset.src;
502
503        video.classList.add('is-active');
504
505    });
506
507});

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.