PageSourceSearch

https://kindlepreneur.com/wp-content/themes/generatepress_child/assets/js/custom-scripts.js?ver=1789150845

js kindlepreneur.com collected 2026-09-24 15:19:02 UTC 26,746 bytes, 802 lines download raw bytes

1jQuery(function($) {
2    // Review Pagination and Form Validation
3        'use strict';
4        
5        // Configuration
6        const REVIEWS_PER_PAGE = 3;
7        
8        // Initialize pagination when DOM is loaded
9        function initializeReviewPagination() {
10            const reviewContainer = document.querySelector('.kp_individual_reviews');
11            if (!reviewContainer) return;
12            
13            const allReviews = Array.from(reviewContainer.querySelectorAll('.kp_single_review'));
14            const loadMoreContainer = reviewContainer.querySelector('.kp_load_more');
15            const loadMoreBtn = reviewContainer.querySelector('.kp_load_more_btn');
16            
17            // If there are 3 or fewer reviews, no pagination needed
18            if (allReviews.length <= REVIEWS_PER_PAGE) {
19                if (loadMoreContainer) {
20                    loadMoreContainer.style.display = 'none';
21                }
22                return;
23            }
24            
25            // Hide all reviews initially
26            allReviews.forEach(review => {
27                review.style.display = 'none';
28            });
29            
30            // Show first batch of reviews
31            let currentlyShowing = 0;
32            showNextBatch();
33            
34            // Add click event to load more button
35            if (loadMoreBtn) {
36                loadMoreBtn.addEventListener('click', function(e) {
37                    e.preventDefault();
38                    showNextBatch();
39                });
40            }
41            
42            function showNextBatch() {
43                const nextBatch = allReviews.slice(currentlyShowing, currentlyShowing + REVIEWS_PER_PAGE);
44                
45                // Show the next batch with animation
46                nextBatch.forEach((review, index) => {
47                    setTimeout(() => {
48                        review.style.display = 'block';
49                        review.style.opacity = '0';
50                        review.style.transform = 'translateY(20px)';
51                        
52                        // Animate in
53                        requestAnimationFrame(() => {
54                            review.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
55                            review.style.opacity = '1';
56                            review.style.transform = 'translateY(0)';
57                        });
58                    }, index * 100); // Stagger the animations
59                });
60                
61                currentlyShowing += REVIEWS_PER_PAGE;
62                
63                // Hide load more button if all reviews are shown
64                if (currentlyShowing >= allReviews.length) {
65                    if (loadMoreContainer) {
66                        loadMoreContainer.style.display = 'none';
67                    }
68                } else {
69                    // Update button text with remaining count
70                    const remaining = allReviews.length - currentlyShowing;
71                    if (loadMoreBtn) {
72                        loadMoreBtn.innerHTML = `Load more reviews (${remaining} remaining) 
73                            <img class="kp_load_more_btn_icon" src="/wp-content/uploads/2025/09/chevron-big-right-2.svg" alt="arrow">`;
74                    }
75                }
76            }
77        }
78        
79        // Review form validation
80        function initializeReviewFormValidation() {
81            const form = document.getElementById('kp_review_form');
82            const ratingError = document.getElementById('kp_rating_error');
83            
84            if (form) {
85                form.addEventListener('submit', function(e) {
86                    const ratingInputs = document.querySelectorAll('input[name="rating"]:checked');
87                    
88                    if (ratingInputs.length === 0) {
89                        e.preventDefault(); // Prevent form submission
90                        ratingError.style.display = 'block';
91                        
92                        // Scroll to the error message
93                        ratingError.scrollIntoView({ behavior: 'smooth', block: 'center' });
94                        
95                        return false;
96                    } else {
97                        ratingError.style.display = 'none';
98                    }
99                });
100                
101                // Hide error message when a rating is selected
102                const ratingInputs = document.querySelectorAll('input[name="rating"]');
103                ratingInputs.forEach(function(input) {
104                    input.addEventListener('change', function() {
105                        if (this.checked) {
106                            ratingError.style.display = 'none';
107                        }
108                    });
109                });
110            }
111        }
112
113        // Empty section detection and free course handling
114        function initializeMiscellaneous() {
115            // Empty section detection
116            document.querySelectorAll("section").forEach(section => {
117                const looper = section.querySelector("[class*='gb-looper']") 
118                            || section.querySelector(".gb-element-2ece090d > div");
119
120                if (!looper) return;
121
122                const loopItems = section.querySelectorAll(".gb-loop-item");
123
124                if (loopItems.length === 0 && looper.children.length === 0) {
125                    section.style.display = "none";
126                }
127            });
128
129            // Desktop free course handling
130            const priceEl = document.querySelector(".kp-course-price");
131            const btnEl = document.querySelector(".kp-course-buy-btn");
132
133            if (priceEl && btnEl) {
134                const priceText = priceEl.textContent.trim();
135
136                if (priceText.toLowerCase() === "$free" || priceText.toLowerCase() === "free") {
137                    priceEl.textContent = "Free";
138                    btnEl.textContent = "Enroll for free";
139                }
140            }
141
142            // Mobile free course handling
143            document.querySelectorAll(".kp-course-mobile-buy-btn").forEach((btnEl) => {
144                const priceEl = btnEl.querySelector(".kp-course-price");
145                if (priceEl) {
146                    const priceText = priceEl.textContent.trim().toLowerCase();
147                    if (priceText === "$free" || priceText === "free") {
148                        btnEl.textContent = "Enroll for Free";
149                    }
150                }
151            });
152        }
153
154        // Initialize all functionality
155        initializeReviewPagination();
156        initializeReviewFormValidation();
157        initializeMiscellaneous();
158
159        // Alternative function for AJAX-based loading (if needed)
160        function loadMoreReviewsAjax(postId, offset = 0) {
161            const loadMoreBtn = document.querySelector('.kp_load_more_btn');
162            const reviewContainer = document.querySelector('.kp_individual_reviews');
163            
164            if (!loadMoreBtn || !reviewContainer) return;
165            
166            // Show loading state
167            const originalText = loadMoreBtn.textContent;
168            loadMoreBtn.textContent = 'Loading...';
169            loadMoreBtn.disabled = true;
170            
171            // AJAX request would go here if needed
172        }
173        
174        // Utility function to animate new reviews
175        function animateNewReviews(reviews) {
176            reviews.forEach((review, index) => {
177                review.style.opacity = '0';
178                review.style.transform = 'translateY(20px)';
179                
180                setTimeout(() => {
181                    review.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
182                    review.style.opacity = '1';
183                    review.style.transform = 'translateY(0)';
184                }, index * 150);
185            });
186        };
187
188
189    // Testimonial Slider
190    if ($('.kp_testimonial_slider').length) {
191        new Swiper('.kp_testimonial_slider', {
192            loop: false,
193            slidesPerView: 2,
194            spaceBetween: 24,
195            speed: 800,
196            navigation: {
197                nextEl: '.swiper-button-next',
198                prevEl: '.swiper-button-prev',
199            },
200            autoplay: false,
201            breakpoints: {
202                1024: { slidesPerView: 2, spaceBetween: 24 },
203                980:  { slidesPerView: 1, spaceBetween: 24 },
204                0:  { slidesPerView: 1, spaceBetween: 24 },
205            },
206        });
207    }
208
209    // Podcast Slider
210    if ($('.kp_pop_podcast_slider').length > 0) {
211        new Swiper('.kp_pop_podcast_slider', {
212            slidesPerView: 3,
213            loop: false,
214            spaceBetween: 24,
215            speed: 800,
216            navigation: {
217                nextEl: '.kp_pop_podcast_slider .swiper-button-next',
218                prevEl: '.kp_pop_podcast_slider .swiper-button-prev',
219            },
220            autoplay: false,
221            breakpoints: {
222                0: { slidesPerView: 1 },
223                768: { slidesPerView: 2 },
224                1024: { slidesPerView: 3 },
225            }
226        });
227    }
228
229    // Podcast TOC functionality
230    if ($(".kp-toc-podcast-single").length) {
231        const tocLinks = $(".kp-toc-list a");
232
233        // Smooth scroll
234        tocLinks.click(function(e) {
235            e.preventDefault();
236            const target = $($(this).attr("href"));
237            if (target.length) {
238                $("html, body").animate({
239                    scrollTop: target.offset().top - 120
240                }, 500);
241            }
242        });
243
244        // Active section highlighting
245        const observer = new IntersectionObserver(entries => {
246            entries.forEach(entry => {
247                if (entry.isIntersecting) {
248                    tocLinks.removeClass("active");
249                    $(".kp-toc-podcast-single .kp-toc-list a[href=\"#" + entry.target.id + "\"]").addClass("active");
250                }
251            });
252        }, {
253            rootMargin: "-140px 0px -70% 0px",
254            threshold: 0
255        });
256
257        // Observe headings
258        tocLinks.each(function() {
259            const target = $($(this).attr("href"));
260            if (target.length) observer.observe(target[0]);
261        });
262    }
263
264     // Guides sort functionality
265    var select = document.querySelector('.kp-guides .kp-guides-sort');
266    if (select) {
267        select.addEventListener('change', function () {
268            var url = new URL(window.location.href);
269            url.searchParams.set('sort', select.value);
270            url.searchParams.delete('page_num'); // reset to 1
271            window.location.href = url.toString();
272        });
273    }
274
275    // ACF content wrapper check
276    $('.kp-acf-content-wrapper').each(function() {
277        const $wrapper = $(this);
278        const $contentDiv = $wrapper.find('> div:last-child');
279        
280        // Check if the content is empty
281        if ($contentDiv.is(':empty') || $.trim($contentDiv.text()) === '') {
282            $wrapper.hide();
283        }
284    });
285
286    /**
287     * -------------------------
288     * Tools Tabs (Click Handler)
289     * -------------------------
290     */
291    $(document).on("click", ".tools-tab", function () {
292        var tab = $(this).data("tab");
293
294        $(".tools-tab").removeClass("active");
295        $(this).addClass("active");
296
297        // sync dropdown with tab
298        $(".kp_all_courses_drop_down").val(tab).trigger("change.select2");
299
300        $(".kp_loading_container").show();
301
302        $("#kp_tools-tabs-content").fadeOut(200, function () {
303            $.ajax({
304                url: toolsTabsAjax.ajax_url,
305                type: "GET",
306                data: {
307                    action: "load_tools_tab",
308                    tab: tab,
309                },
310                success: function (data) {
311                    $("#kp_tools-tabs-content").html(data).fadeIn(400);
312                    $(".kp_loading_container").hide();
313                },
314            });
315        });
316    });
317
318    /**
319     * -------------------------
320     * Tools Dropdown (Select2)
321     * -------------------------
322     */
323    $(".kp_all_courses_drop_down").select2({
324        minimumResultsForSearch: Infinity,
325        width: "100%",
326    });
327
328    // Change handler
329    $(document).on("change", ".kp_all_courses_drop_down", function () {
330        var tab = $(this).val();
331
332        if ($(".kp_loading_container").is(":visible")) return;
333
334        // sync tab buttons
335        $(".tools-tab").removeClass("active");
336        $('.tools-tab[data-tab="' + tab + '"]').addClass("active");
337
338        $(".kp_loading_container").show();
339
340        $("#kp_tools-tabs-content").fadeOut(200, function () {
341            $.ajax({
342                url: toolsTabsAjax.ajax_url,
343                type: "GET",
344                data: {
345                    action: "load_tools_tab",
346                    tab: tab,
347                },
348                success: function (data) {
349                    $("#kp_tools-tabs-content").html(data).fadeIn(400);
350                    $(".kp_loading_container").hide();
351
352                    $("html, body").animate(
353                        {
354                            scrollTop: $("#kp_tools-tabs-content").offset().top - 50,
355                        },
356                        400
357                    );
358                },
359            });
360        });
361    });
362
363    /**
364     * -------------------------
365     * Tools Pagination
366     * -------------------------
367     */
368    $(document).on("click", ".tools-pagination a", function (e) {
369        e.preventDefault();
370
371        var container = $(this).closest(".kp_tools-tab-content");
372        var containerId = container.attr("id");
373        var tab = "";
374
375        if (containerId) {
376            tab = containerId.replace("tab-", "");
377        } else {
378            tab = $(".tools-tab.active").data("tab") || "all";
379        }
380
381        var page = $(this).data("page");
382		if (typeof page === "undefined" || page === null) return; 
383
384        $(".kp_loading_container").show();
385
386        $("#kp_tools-tabs-content").fadeOut(200, function () {
387            $.ajax({
388                url: toolsTabsAjax.ajax_url,
389                type: "GET",
390                data: {
391                    action: "load_tools_tab",
392                    tab: tab,
393                    paged: page,
394                },
395                success: function (data) {
396                    $("#kp_tools-tabs-content").html(data).fadeIn(400);
397                    $(".kp_loading_container").hide();
398
399                    $("html, body").animate(
400                        {
401                            scrollTop: $("#kp_tools-tabs-content").offset().top - 50,
402                        },
403                        400
404                    );
405                },
406            });
407        });
408    });
409
410    /**
411     * -------------------------
412     * Self-Publishers Accordion
413     * -------------------------
414     */
415    const imgEl = $("#kp_accordion-image");
416
417    const spinner = $("<img>", {
418        src: "/wp-content/uploads/2025/09/kp-loading.gif",
419        class: "kp-spinner",
420        css: {
421            position: "absolute",
422            top: "50%",
423            left: "50%",
424            width: "40px",
425            height: "40px",
426            transform: "translate(-50%, -50%)",
427            zIndex: 10,
428            display: "none",
429        },
430    });
431
432    if (!imgEl.parent().hasClass("kp-image-wrapper")) {
433        imgEl.wrap(
434            '<div class="kp-image-wrapper" style="position: relative; display: inline-block;"></div>'
435        );
436        imgEl.parent().append(spinner);
437    }
438
439    $(document).on("click", ".kp-accordion-item", function () {
440        const newImgSrc = $(this).attr("data-img");
441
442        if (!newImgSrc || imgEl.attr("src") === newImgSrc) return;
443
444        spinner.show();
445        imgEl.css("opacity", 0.3);
446
447        const preloader = new Image();
448        preloader.src = newImgSrc;
449
450        preloader.onload = function () {
451            imgEl.attr("src", newImgSrc);
452            setTimeout(() => {
453                imgEl.css("opacity", 1);
454                spinner.hide();
455            }, 200);
456        };
457    });
458
459    /**
460     * ----------------------------------- *
461     * Interview Page - Image Carousal     *
462     * ----------------------------------- *
463     ***/
464    const loopEnabled = false;
465
466    const $swiperContainer = $(".swiper-container .swiper-wrapper");
467    const $slides = $swiperContainer.find(".swiper-slide");
468
469    // Only clone slides if loop is enabled AND only 3 slides are present
470    if (loopEnabled && $slides.length === 3) {
471        $slides.each(function () {
472            const $clone = $(this).clone();
473            $swiperContainer.append($clone);
474        });
475    }
476
477    const swiper = new Swiper(".swiper-container", {
478        loop: loopEnabled,
479        speed: 800,
480        centeredSlides: true,
481        slidesPerView: "auto",
482        initialSlide: 1,
483        /*
484        autoplay: {
485            delay: 4000,
486            disableOnInteraction: false,
487        },
488        */
489        navigation: {
490            nextEl: ".swiper-button-next-new",
491            prevEl: ".swiper-button-prev-new",
492        },
493        breakpoints: {
494            0: {
495                slidesPerView: 1,
496                spaceBetween: 12,
497                centeredSlides: false,
498            },
499            981: {
500                slidesPerView: "auto",
501                spaceBetween: 0,
502                centeredSlides: true,
503            },
504        },
505    });
506
507    /**
508     * -------------------------
509     * VIP Resources Pagination
510     * -------------------------
511     */
512    let $vipContainer = $('#vip-resources-container');
513    if ($vipContainer.length) {
514        let $vipLoader = $('.kp_loading_container');
515        let $vipPagination = $('.kp_tools_pagination');
516        let vipPostsPerPage = parseInt($vipContainer.data('posts-per-page')) || 6;
517        let vipCurrentPage = 1;
518
519        function loadVipPosts(page = 1) {
520            vipCurrentPage = parseInt(page, 10) || 1;
521
522            $vipContainer.fadeOut(300);
523            $vipLoader.show();
524
525            $.post(vipResourcesAjax.ajax_url, {
526                action: 'vip_resources_ajax_load_paged',
527                page: vipCurrentPage,
528                ppp: vipPostsPerPage
529            }, function (res) {
530                if (res && res.success) {
531                    $vipContainer.html(res.data.html);
532                    $vipPagination.html(res.data.pagination);
533
534                    $vipLoader.hide();
535                    $vipContainer.fadeIn(300);
536                } else {
537                    $vipContainer.html('<p>No posts found.</p>').fadeIn(300);
538                    $vipLoader.hide();
539                    $vipPagination.empty();
540                }
541            });
542        }
543
544        // Initial load
545        loadVipPosts();
546
547        $(document).on('click', '.kp_tools_pagination a', function (e) {
548            e.preventDefault();
549
550            let $a = $(this);
551            let paged = $a.data('page');
552
553            if (!paged) {
554                let href = $a.attr('href') || '';
555                let match = href.match(/[?&]paged=(\d+)/);
556                if (match) {
557                    paged = match[1];
558                } else {
559                    // fallback if it's prev/next without href
560                    if ($a.hasClass('prev')) {
561                        paged = vipCurrentPage > 1 ? vipCurrentPage - 1 : 1;
562                    } else if ($a.hasClass('next')) {
563                        paged = vipCurrentPage + 1;
564                    } else {
565                        let txt = $a.text().trim();
566                        paged = $.isNumeric(txt) ? txt : vipCurrentPage;
567                    }
568                }
569            }
570
571            paged = parseInt(paged, 10) || 1;
572            loadVipPosts(paged);
573        });
574    }
575
576    /**
577     * -------------------------
578     * VIP Coupons
579     * -------------------------
580     */
581
582    $(document).on('click', '.kp_tools-page-numbers li[data-page]', function (e) {
583    e.preventDefault();
584
585    var $li = $(this);
586    var page = parseInt($li.attr('data-page'), 10);
587    if (!page || isNaN(page)) return;
588
589    if ($li.hasClass('kp_page_current')) return;
590
591    $('#kp_id_coupon_wrapper').stop(true, true).fadeOut(400, function () {
592      $('.kp_loading_container').show();
593    });
594
595    $.ajax({
596      url: vipCouponsAjax.ajax_url,
597      type: 'POST',
598      dataType: 'json',
599      data: {
600        action: 'kp_load_vip_coupons',
601        page: page,
602        nonce: vipCouponsAjax.nonce
603      },
604      success: function (response) {
605        if (response.success) {
606          $('#kp_id_coupon_wrapper').parent().html(response.data);
607          $('.kp_loading_container').hide();
608          $('#kp_id_coupon_wrapper').hide().fadeIn(400);
609        } else {
610          $('.kp_loading_container').hide();
611          $('#kp_id_coupon_wrapper').fadeIn(400);
612        }
613      },
614      error: function () {
615        $('.kp_loading_container').hide();
616        $('#kp_id_coupon_wrapper').fadeIn(400);
617      }
618    });
619  });
620
621// 	===================================================================================================
622
623// ===== Kindlepreneur Search Page (kp-search-page) =====
624(function(){
625	const root = document.querySelector('.kp-search-page');
626	if (!root) return;
627
628	const ajax  = root.getAttribute('data-ajax');
629	const nonce = root.getAttribute('data-nonce');
630	const q     = root.getAttribute('data-q') || '';
631
632	root.addEventListener('click', async (e) => {
633		const btn = e.target.closest('.kp-search-page__more');
634		if (!btn) return;
635
636		const section = btn.closest('.kp-search-page__section');
637		const gridId  = btn.getAttribute('aria-controls');
638		const grid    = gridId ? document.getElementById(gridId) : section.querySelector('.kp-search-page__grid');
639
640		const type    = btn.getAttribute('data-type');
641		const state   = btn.getAttribute('data-state') || 'collapsed';
642		const moreLbl = btn.getAttribute('data-more-label') || 'See more';
643		const lessLbl = btn.getAttribute('data-less-label') || 'See less';
644		const labelEl = btn.querySelector('.kp-search-page__more-label');
645
646		// COLLAPSE to initial 6 (See less)
647		if (state === 'expanded') {
648			const totalAdded = parseInt(btn.getAttribute('data-total-added') || '0', 10);
649			for (let i = 0; i < totalAdded; i++) {
650				if (grid && grid.lastElementChild) {
651					grid.removeChild(grid.lastElementChild);
652				}
653			}
654			// Reset back to initial state (first 6)
655			const initialOffset = parseInt(btn.getAttribute('data-initial') || '6', 10);
656			btn.setAttribute('data-offset', String(initialOffset));
657			btn.setAttribute('data-total-added', '0');
658			btn.setAttribute('data-state', 'collapsed');
659			btn.setAttribute('aria-expanded', 'false');
660			btn.classList.remove('is-expanded');
661			if (labelEl) labelEl.textContent = moreLbl;
662			return;
663		}
664
665		// EXPAND (fetch next page)
666		const offset = parseInt(btn.getAttribute('data-offset') || '0', 10);
667		const limit  = parseInt(btn.getAttribute('data-limit')  || '6', 10);
668
669		btn.disabled = true;
670		if (labelEl) labelEl.textContent = 'Loading…';
671
672		try {
673			const form = new FormData();
674			form.append('action', 'kp_search_page_load_more');
675			form.append('nonce', nonce);
676			form.append('post_type', type);
677			form.append('offset', offset);
678			form.append('limit', limit);
679			form.append('q', q);
680
681			const res  = await fetch(ajax, { method: 'POST', body: form, credentials: 'same-origin' });
682			const json = await res.json();
683
684			if (json.success && json.data) {
685				const { html, added, next_offset, has_more } = json.data;
686
687				if (html) {
688					const temp  = document.createElement('div');
689					temp.innerHTML = html;
690					const nodes = Array.from(temp.children);
691					if (grid && nodes.length) {
692						grid.append(...nodes);
693					}
694				}
695
696				// Track how many we added in this session
697				const prevAdded = parseInt(btn.getAttribute('data-total-added') || '0', 10);
698				const newTotal  = prevAdded + (parseInt(added || 0, 10) || 0);
699				btn.setAttribute('data-total-added', String(newTotal));
700
701				// Update next offset
702				btn.setAttribute('data-offset', String(next_offset));
703
704				if (has_more) {
705					// Keep showing "See more …"
706					if (labelEl) labelEl.textContent = moreLbl;
707				} else {
708					// No more to fetch → switch to "See less"
709					btn.setAttribute('data-state', 'expanded');
710					btn.setAttribute('aria-expanded', 'true');
711					btn.classList.add('is-expanded');
712					if (labelEl) labelEl.textContent = lessLbl;
713				}
714			} else {
715				// Restore more label on failure/empty
716				if (labelEl) labelEl.textContent = moreLbl;
717			}
718		} catch (err) {
719			console.error('Load more failed', err);
720			if (labelEl) labelEl.textContent = 'Try again';
721		} finally {
722			btn.disabled = false;
723		}
724	});
725})();
726	
727// 	===================================================================================================
728
729	/*---------------Hide title on hover for images and links--------------------*/	
730	$(function() {
731	  // Hide title on hover for links and images
732	  $('body').on('mouseenter', 'a[title], img[title]', function() {
733		$(this).data('tmp_title', $(this).attr('title'));
734		$(this).removeAttr('title');
735	  }).on('mouseleave', 'a, img', function() {
736		var tmp = $(this).data('tmp_title');
737		if (tmp) {
738		  // Delay restoring the title a bit to prevent flicker/tooltips
739		  var el = $(this);
740		  setTimeout(function() {
741			el.attr('title', tmp);
742		  }, 200); // 200ms delay works well
743		}
744	  });
745	});
746
747	/*---------------LINK & IMAGE TITLES--------------------*/	
748	$(function() {
749	  function addTitles() {
750		// LINKS
751		$('a').each(function() {
752		  var this_element = $(this);
753		  var link_text = this_element.text().trim();
754
755		  if (link_text === '') {
756			var img = this_element.find('img');
757			if (img.length && img.attr('alt')) {
758			  link_text = img.attr('alt').trim();
759			} else {
760			  var href = this_element.attr('href') || '';
761			  link_text = href
762				.replace(/^https?:\/\//, '')
763				.replace(/^www\./, '')
764				.replace(/\/$/, '');
765			}
766		  }
767
768		  if (link_text) {
769			this_element.attr('title', link_text);
770		  }
771		});
772
773		// IMAGES
774		$('img').each(function() {
775		  var this_image = $(this);
776		  var img_title = this_image.attr('title');
777		  var img_alt = this_image.attr('alt');
778		  var img_src = this_image.attr('src');
779
780		  if (!img_title || img_title.trim() === '') {
781			if (img_alt && img_alt.trim() !== '') {
782			  img_title = img_alt.trim();
783			} else if (img_src) {
784			  img_title = img_src.split('/').pop().split('.')[0]
785				.replace(/[-_]+/g, ' ')
786				.replace(/\b\w/g, function(c) { return c.toUpperCase(); });
787			} else {
788			  img_title = 'Image';
789			}
790			this_image.attr('title', img_title);
791		  }
792		});
793	  }
794
795	  // Run once now
796	  addTitles();
797
798	  setTimeout(addTitles, 4000);
799	});
800
801	
802});

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.