PageSourceSearch

https://www.mwc.org.sg/assets/js/script.js

js mwc.org.sg collected 2026-09-26 10:31:42 UTC 134,280 bytes, 3,430 lines download raw bytes

1// for Assoc Link Swiper
2function assocLinkSwiper() {
3    const swiper = new Swiper(".swiper", {
4        slidesPerView: 1,
5        direction: "horizontal",
6        spaceBetween: 40,
7        pagination: {
8            el: ".swiper-pagination",
9            clickable: true,
10        },
11        enabled: true,
12        breakpoints: {
13            768: {
14                enabled: false,
15            },
16        },
17    });
18
19    function resetSwiperOnResize() {
20        swiper.update();
21        const activeIndex = swiper.activeIndex;
22        if (activeIndex !== 0) {
23            swiper.slideTo(0);
24        }
25    }
26
27    window.addEventListener("resize", resetSwiperOnResize);
28}
29document.addEventListener("DOMContentLoaded", function () {
30    if (typeof Swiper !== "undefined") {
31        assocLinkSwiper();
32    } else {
33        console.error("Swiper library is not loaded.");
34    }
35});
36
37function checkUserAgent() {
38    // if($('.app-store-link').length > 0) {
39    if (/Android/i.test(navigator.userAgent)) {
40        $("body").attr("userAgent", "android");
41    } else {
42        if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
43            $("body").attr("userAgent", "ios");
44        } else {
45            $("body").attr("userAgent", "desktop");
46        }
47    }
48    // }
49}
50function openChatBot() {
51    $(".chatbot").on("click", function (e) {
52        e.preventDefault();
53        $keyreply.dispatch("OPEN_CHAT_WINDOW");
54        $keyreply.dispatch("START");
55    });
56}
57function inpageNav() {
58    var navBar = $("#myNavbar");
59    if (navBar.length > 0) {
60        $(window).on("orientationchange", function () {
61            window.location.reload();
62        });
63    }
64    if (navBar.find(".nav-item").length < 5) {
65        navBar.addClass("centered");
66    }
67    var megaMenu = $(".navbar.navbar-expand-lg");
68    navBar.find(".nav.nav-pills .nav-item .nav-link").each(function () {
69        var itemId = $(this).attr("href");
70        if ($(itemId).length < 1) {
71            $(this).closest(".nav-item").remove();
72        }
73    });
74    if (megaMenu.length > 0) {
75        var lastScrollTop = 0;
76        $(window).on("scroll", function () {
77            var st = $(this).scrollTop();
78            if (st < 20) {
79                megaMenu.removeAttr("data-scrolling");
80                megaMenu.removeClass("otw-scrolling");
81            } else {
82                if (st > lastScrollTop) {
83                    // downscroll code
84                    megaMenu.addClass("otw-scrolling");
85                    megaMenu.attr("data-scrolling", false);
86                    // $('.navbar-toggler[aria-expanded="true"]').trigger('click');
87                } else {
88                    // upscroll code
89                    megaMenu.addClass("otw-scrolling");
90                    megaMenu.attr("data-scrolling", true);
91                }
92            }
93            lastScrollTop = st;
94        });
95    }
96    let flowing = false;
97    if (navBar.length > 0) {
98        navBar.find(".nav-link").on("click", function (e) {
99            e.preventDefault();
100            if (flowing) return;
101            flowing = true;
102            navBar.find(".nav.nav-pills .nav-link.active").removeClass("active");
103            $(this).addClass("active");
104            var activeItemLeft = $(this).position().left;
105            var activeItemWidth = $(this).innerWidth();
106            $(".tab-bar-anim").css({
107                width: activeItemWidth,
108                left: activeItemLeft,
109            });
110
111            const section = $(this)[0].getAttribute("href");
112            document.querySelector(section).scrollIntoView({ behavior: "instant" });
113
114            setTimeout(() => {
115                flowing = false;
116            }, 500);
117        });
118        var hash = window.location.hash;
119        if (hash && window.performance.navigation.type == 1) {
120            var activePageSection = navBar.find(
121                '.nav-link[href="' + window.location.hash + '"]'
122            );
123
124            if (activePageSection.length > 0) {
125                var activeItemLeft = activePageSection.position().left;
126                var activeItemWidth = activePageSection.innerWidth();
127
128                $(".tab-bar-anim").css({
129                    width: activeItemWidth,
130                    left: activeItemLeft,
131                });
132            }
133        }
134        var firstSectionPos = $(".page-section:first-child")?.offset()?.top - 64;
135
136        $(window).on("scroll", function (e) {
137            e.preventDefault();
138            if (
139                $(window).scrollTop() > firstSectionPos &&
140                $(window).scrollTop() < $(".footer").offset().top - 150
141            ) {
142                megaMenu.slideUp("fast");
143                navBar.attr("sticky", true);
144                navBar.slideDown("fast");
145                if ($(".nav li:not(:last-child)").css("display") !== "none") {
146                    if (!flowing) {
147                        requestAnimationFrame(() => {
148                            var activeItemLeft = navBar
149                                .find(".nav-link.active")
150                                .position().left;
151
152                            console.log("active", activeItemLeft);
153                            var activeItemWidth = navBar
154                                .find(".nav-link.active")
155                                .innerWidth();
156                            $(".tab-bar-anim").css({
157                                width: activeItemWidth,
158                                left: activeItemLeft,
159                            });
160                        });
161                    }
162                }
163            } else {
164                navBar.attr("sticky", false);
165                navBar.slideUp("fast");
166                megaMenu.slideDown("fast");
167            }
168
169            var scrollTop = $(window).scrollTop(),
170                divOffset = navBar.offset().top,
171                dist = divOffset - scrollTop;
172            if (dist > 16) {
173                $("#myNavbar ul li:first-child a").addClass("active");
174            }
175        });
176
177        var activeTextFirstTime = navBar
178            .find(".nav.nav-pills .nav-item:first-child span")
179            .text();
180        navBar.find(".nav.nav-pills").each(function () {
181            $(this).append(
182                $(document.createElement("li"))
183                    .addClass("nav-item dropdown nav-list")
184                    .attr("id", "myNavbarMob")
185                    .html(
186                        '<a href="#" class="dropdown-toggle" data-bs-toggle="dropdown">' +
187                        activeTextFirstTime +
188                        '</a><div class="dropdown-menu"></div>'
189                    )
190            );
191            $(this)
192                .find(".nav-link")
193                .each(function () {
194                    var href = $(this).attr("href");
195                    $(this)
196                        .clone()
197                        .contents()
198                        .wrap('<a href="' + href + "-mob" + '" class="dropdown-item" />')
199                        .parent()
200                        .appendTo($("#myNavbarMob .dropdown-menu"));
201
202                    const navBarMob = $("#myNavbarMob");
203                    if (navBarMob.length > 0) {
204                        navBarMob.find("a.dropdown-item").on("click", function () {
205                            const newText = $(this).find("span").text();
206                            navBarMob.find(".dropdown-toggle.active").text(newText);
207                        });
208                        $(window).on("scroll", function () {
209                            const linkitems = navBarMob.find("a.dropdown-item.active");
210                            const newText = $(linkitems).find("span").text();
211                            navBarMob.find(".dropdown-toggle.active").text(newText);
212                        });
213                    }
214                });
215        });
216
217        if ($(window).width() < 992) {
218            $(".page-section").each(function () {
219                var that = $(this);
220                var sectionId = $(this).attr("id");
221                $(this).attr("id", sectionId + "-mob");
222            });
223        }
224
225        window.addEventListener(
226            "resize",
227            function () {
228                if ($(window).width() < 992) {
229                    $(".page-section").each(function () {
230                        var sectionId = $(this).attr("id");
231                        var arr = sectionId.split("-");
232                        var myNewArray = arr.filter(function (elem, index, self) {
233                            return index === self.indexOf(elem);
234                        });
235                        if (myNewArray.indexOf("mob") != -1) {
236                            sectionId = myNewArray.join("-");
237                            $(this).attr("id", sectionId);
238                        } else {
239                            $(this).attr("id", sectionId + "-mob");
240                        }
241                    });
242                } else {
243                    $(".page-section").each(function () {
244                        var sectionId = $(this).attr("id");
245                        var str = sectionId.split("-mob");
246                        $(this).attr("id", str[0]);
247                    });
248                }
249            },
250            true
251        );
252    }
253}
254function highlightText(element, regex) {
255    let text = element.html();
256    text = text.replace(/(<span class="highlight">|<\/span>)/gim, "");
257
258    const newText = text
259        .replace("&amp;", "&")
260        .replace(regex, '<span class="highlight">$&</span>');
261    element.html(newText);
262}
263function alphabetFilter() {
264    if ($("[data-search-unions]").length > 0) {
265        var resultSection = $("[data-search-unions-result]");
266        var groupLength = resultSection.find(".alphabet-group").length;
267        $("[data-search-unions]").on("keyup search", function () {
268            var value = $(this).val().toLowerCase();
269
270            resultSection.find(".icon-text").filter(function () {
271                $(this)
272                    .closest(".col-lg-4")
273                    .toggle($(this).text().toLowerCase().indexOf(value) > -1);
274
275                // highlight text if match
276                if ($(this).text().toLowerCase().indexOf(value) > -1) {
277                    const regex = new RegExp(value, "gi");
278                    highlightText($(this).find(".title"), regex);
279                    highlightText($(this).find(".editor"), regex);
280                }
281            });
282            resultSection.find(".alphabet-group").filter(function () {
283                $(this).toggle(
284                    $(this).find(".icon-text").text().toLowerCase().indexOf(value) > -1
285                );
286            });
287            if (resultSection.find(".alphabet-group:hidden").length === groupLength) {
288                $("[data-no-result]").removeClass("d-none");
289            } else {
290                $("[data-no-result]").addClass("d-none");
291            }
292        });
293    }
294}
295function glossaryFilter() {
296    if ($("[data-search-glossaries]").length > 0) {
297        var resultSection = $("[data-search-glossaries-result]");
298        var groupLength = resultSection.find(".alphabet-group").length;
299        $("[data-search-glossaries]").on("keyup search", function () {
300            var value = $(this).val().toLowerCase();
301            resultSection.find("[data-glossary-term]").filter(function () {
302                $(this)
303                    .closest(".glossary-term")
304                    .toggle($(this).text().toLowerCase().indexOf(value) > -1);
305
306                // highlight text if match
307                if ($(this).text().toLowerCase().indexOf(value) > -1) {
308                    const regex = new RegExp(value, "gi");
309                    highlightText($(this), regex);
310                }
311            });
312            resultSection
313                .find(".alphabet-group, .result-section")
314                .filter(function () {
315                    $(this).toggle(
316                        $(this)
317                            .find("[data-glossary-term]")
318                            .text()
319                            .toLowerCase()
320                            .indexOf(value) > -1
321                    );
322                });
323
324            if (resultSection.find(".alphabet-group:hidden").length === groupLength) {
325                $("[data-no-result]").removeClass("d-none");
326            } else {
327                $("[data-no-result]").addClass("d-none");
328            }
329        });
330    }
331}
332function videoCarousel() {
333    var videoCarousel = $("[data-video-carousel]");
334    if (videoCarousel.length > 0) {
335        videoCarousel
336            .find(".slider-for")
337            .slick({
338                slidesToShow: 1,
339                slidesToScroll: 1,
340                pauseOnHover: false,
341                infinite: true,
342                arrows: false,
343                fade: true,
344                asNavFor: ".slider-nav",
345            })
346            .on("beforeChange", function (event, slick, currentSlide, nextSlide) {
347                var current = $(slick.$slides[currentSlide]);
348                current.html(current.html());
349            });
350
351        videoCarousel.find(".slider-nav").slick({
352            slidesToShow: 3,
353            slidesToScroll: 1,
354            asNavFor: ".slider-for",
355            dots: false,
356            arrows: false,
357            infinite: true,
358            focusOnSelect: true,
359            mobileFirst: true,
360            centerMode: false,
361            initialSlide: 1,
362            variableWidth: true,
363            responsive: [
364                {
365                    breakpoint: 992,
366                    settings: {
367                        slidesToShow: 4,
368                        slidesToScroll: 1,
369                        vertical: true,
370                        verticalSwiping: true,
371                        variableWidth: false,
372                    },
373                },
374            ],
375        });
376    }
377}
378function searchAutoComplete(input) {
379    var options = {
380        url: function (phrase) {
381            let url = input.data("url");
382            if (input.data("url").indexOf("http") < 0) {
383                url = window.location.origin + url;
384            }
385            url = new URL(url);
386            let params = new URLSearchParams(url.search);
387            params.set("t", input.val());
388            url.search = params.toString();
389            return url;
390        },
391
392        getValue: function (element) {
393            return element.value;
394        },
395        minCharNumber: 0,
396        ajaxSettings: {
397            dataType: "json",
398            method: "POST",
399            data: {
400                dataType: "json",
401            },
402            success: function (response) {
403                if (
404                    response.length == 0 &&
405                    input.val().length > 1 &&
406                    $("#autocomplete-no-result").length < 1
407                ) {
408                    let notFoundDiv = '<p id="autocomplete-no-result"> Not found</p>';
409                    $(".easy-autocomplete-container").append(notFoundDiv);
410                }
411                if (input.val().length == 0 || response.length > 0) {
412                    $("#autocomplete-no-result").remove();
413                }
414            },
415        },
416
417        preparePostData: function (data) {
418            data.phrase = input.val();
419            return data;
420        },
421        requestDelay: 200,
422        template: {
423            type: "links",
424            fields: {
425                link: "url",
426            },
427        },
428        list: {
429            match: {
430                enabled: false,
431            },
432        },
433    };
434    input.easyAutocomplete(options);
435}
436
437function formValidation() {
438    var forms = $(".needs-validation");
439
440    // Loop over them and prevent submission
441    Array.prototype.slice.call(forms).forEach(function (form) {
442        form.addEventListener(
443            "submit",
444            function (event) {
445                if (!form.checkValidity()) {
446                    event.preventDefault();
447                    event.stopPropagation();
448                }
449
450                form.classList.add("was-validated");
451            },
452            false
453        );
454    });
455    $(".form-select").selectmenu();
456    $(".datepicker").datepicker({
457        dateFormat: "dd/mm/yy",
458    });
459}
460
461function coveoRendering() {
462    let coveoFlagDesktop = false;
463    let coveoFlagMobile = false;
464    var accessToken = $("body").attr("data-accessToken");
465    var organizationId = $("body").attr("data-organizationId");
466    var searchHub = $("body").attr("data-searchHub");
467
468    if (accessToken && organizationId && searchHub) {
469        // initialize for Search Result page
470        (async () => {
471            await customElements.whenDefined("atomic-search-interface");
472            let searchInterface = $(".coveo-search-results atomic-search-interface");
473            if (searchInterface.length > 0) {
474                searchInterface = searchInterface[0];
475                await searchInterface.initialize({
476                    platformUrl: "https://platform-au.cloud.coveo.com",
477                    accessToken: accessToken,
478                    organizationId: organizationId,
479                    searchHub: searchHub,
480                });
481                searchInterface.executeFirstSearch();
482                searchInterface.i18n.addResourceBundle("en", "caption-filetype", {
483                    ".html": "html",
484                });
485            }
486        })();
487        // initialize for Search Dropdown once click on Search Icon at the first time
488        $(".search-group.dropdown-toggle").on("show.bs.dropdown", function () {
489            if (
490                (!coveoFlagDesktop && $(window).width() > 991) ||
491                (!coveoFlagMobile && $(window).width() <= 991)
492            ) {
493                (async () => {
494                    await customElements.whenDefined("atomic-search-interface");
495                    let searchInterface = $(this)
496                        .closest(".nav-item")
497                        .find("atomic-search-interface");
498                    if (searchInterface.length > 0) {
499                        searchInterface = searchInterface[0];
500                        await searchInterface.initialize({
501                            platformUrl: "https://platform-au.cloud.coveo.com",
502                            accessToken: accessToken,
503                            organizationId: organizationId,
504                            searchHub: searchHub,
505                        });
506                        searchInterface.executeFirstSearch();
507                        searchInterface.i18n.addResourceBundle("en", "caption-filetype", {
508                            ".html": "html",
509                        });
510                    }
511                })();
512                if ($(window).width() > 991) {
513                    coveoFlagDesktop = true;
514                } else {
515                    coveoFlagMobile = true;
516                }
517            }
518        });
519    }
520}
521
522function fancyBoxRendering() {
523    if ($(".fancybox").length > 0) {
524        $(".fancybox").fancybox({
525            beforeShow: function () {
526                this.inner.append(
527                    '<span class="image-count">' +
528                    (this.index + 1) +
529                    " / " +
530                    this.group.length
531                ) + "</span>";
532            },
533        });
534    }
535    if ($(".fancybox-media").length > 0) {
536        $(".fancybox-media").fancybox({
537            openEffect: "none",
538            closeEffect: "none",
539            prevEffect: "none",
540            nextEffect: "none",
541            arrows: false,
542            helpers: {
543                media: {},
544                buttons: {},
545            },
546            beforeClose: function () {
547                var video = this.inner.find("video")[0];
548                video.pause();
549                video.currentTime = 0;
550            },
551        });
552    }
553}
554
555function closeAnnouncement() {
556    const closeButton = document.getElementById("close-button");
557    const tab = document.getElementById("announcement-tab");
558
559    closeButton?.addEventListener("click", () => {
560        tab?.classList?.add("close-announcement");
561    });
562}
563
564function compassAnimation() {
565    const contentContainer = document.getElementById("contentContainer");
566    const blockContainer = document.getElementById("blockContainer");
567
568    document
569        ?.getElementById("coloured-block-1")
570        ?.querySelector("#top")
571        ?.classList.add(`colour-1`);
572    document
573        ?.getElementById("coloured-block-1")
574        ?.querySelector("#side")
575        ?.setAttribute("fill", `url(#color1`);
576
577    let selectedBlock;
578    let totalBlock = blockContainer?.childElementCount;
579
580    if (blockContainer?.children !== undefined) {
581        Array?.from(blockContainer?.children)?.forEach(function (childDiv, index) {
582            childDiv?.addEventListener("click", function () {
583                selectedBlock = index + 1;
584
585                Array?.from(blockContainer?.children).forEach(function (
586                    otherChildDiv,
587                    otherIndex
588                ) {
589                    if (otherIndex !== index) {
590                        var otherTopElement = otherChildDiv.querySelector("#top");
591                        var sideElement = otherChildDiv.querySelector("#side");
592                        otherTopElement.classList.add("colour-0");
593                        sideElement.setAttribute("fill", `url(#grey)`);
594                    }
595                });
596
597                var topElement = childDiv.querySelector("#top");
598                var sideElement = childDiv.querySelector("#side");
599
600                topElement.classList.remove(`colour-0`);
601                topElement.classList.add(`colour-${index + 1}`);
602                sideElement.setAttribute("fill", `url(#color${index + 1})`);
603
604                Array.from(contentContainer?.children).forEach(function (
605                    textDiv,
606                    index
607                ) {
608                    if (selectedBlock === index + 1) {
609                        textDiv.classList.remove("hide-block");
610                    } else {
611                        textDiv.classList.add("hide-block");
612                    }
613                });
614            });
615        });
616    }
617
618    window.addEventListener("scroll", () => {
619        const scrollPosition = window.scrollY + 500;
620
621        // Calculate the index based on the scroll position
622        const index = Math.floor(scrollPosition / (window.innerHeight * 2));
623        // Make sure the index is within the bounds of the texts array
624        if (index >= 0 && index < totalBlock) {
625            // Update the selected block based on the scroll
626            selectedBlock = index + 1;
627
628            Array.from(blockContainer.children).forEach(function (childDiv, index) {
629                var topElement = childDiv.querySelector("#top");
630                var sideElement = childDiv.querySelector("#side");
631
632                if (selectedBlock === index + 1) {
633                    topElement.classList.remove(`colour-0`);
634                    topElement.classList.add(`colour-${selectedBlock}`);
635                    sideElement.setAttribute("fill", `url(#color${selectedBlock})`);
636                } else {
637                    topElement.classList.add(`colour-0`);
638                    sideElement.setAttribute("fill", `url(#grey)`);
639                }
640            });
641
642            // Handle showing/hiding text content here based on the selected block
643            Array.from(contentContainer.children).forEach(function (
644                textDiv,
645                textIndex
646            ) {
647                if (selectedBlock === textIndex + 1) {
648                    textDiv.classList.remove("hide-block");
649                } else {
650                    textDiv.classList.add("hide-block");
651                }
652            });
653        }
654    });
655}
656
657function tpeQuizLogic() {
658    const question1Input = document.querySelector('[data-sc-field-name="Q1"]');
659    const question2Input = document.querySelector('[data-sc-field-name="Q2"]');
660    const question3Input = document.querySelector('[data-sc-field-name="Q3"]');
661    const question4Input = document.querySelector('[data-sc-field-name="Q4"]');
662    const question5Input = document.querySelector('[data-sc-field-name="Q5"]');
663    const question6Input = document.querySelector('[data-sc-field-name="Q6"]');
664    const question7Input = document.querySelector('[data-sc-field-name="Q7"]');
665
666    const response = {
667        question1: "",
668        question2: "",
669        question3: "",
670        question4: "",
671        question5: "",
672        question6: "",
673        question7: "",
674        question8: "",
675        questionqna: { name: "", company: "", email: "", contact: "", note: "" },
676    };
677
678    const answers = {
679        Items: [],
680    };
681
682    for (let i = 1; i <= 8; i++) {
683        const questionObj = {
684            Question: `Question ${i}`,
685            Answers: [],
686        };
687
688        answers.Items.push(questionObj);
689    }
690
691    // CONTROLS FOR QUESTION 1
692    const question1 = document.querySelectorAll(".question-1-option");
693    let selectedOption = null;
694    question1.forEach((ques) => {
695        ques.addEventListener("click", () => {
696            // Check if there is a previously selected option
697            if (selectedOption) {
698                selectedOption.classList.remove("selected");
699            }
700
701            ques.classList.add("selected");
702            selectedOption = ques;
703
704            const optionText = ques.querySelector(".text").textContent.trim();
705            answers.Items[0].Answers = [];
706            answers.Items[0].Answers.push(optionText);
707            question1Input.nodeValue = optionText;
708            question1Input.value = optionText;
709
710            if (answers.Items[0].Answers.length > 0) {
711                nextButton1.classList.add("activate-button");
712                nextButton1.disabled = false;
713            }
714        });
715    });
716
717    // CONTROLS FOR QUESTION 2
718    const dropdownButton = document.getElementById("dropdown-button");
719    const dropdownMenu = document.getElementById("dropdown-menu");
720    const dropdownIcon = document.getElementById("dropdown-icon");
721    const dropdownOptions = dropdownMenu?.querySelectorAll("li");
722
723    dropdownButton?.addEventListener("click", () => {
724        if (answers.Items[1].Answers.length > 0) {
725            nextButton2.classList.add("activate-button");
726            nextButton2.disabled = false;
727        }
728
729        dropdownIcon.classList.toggle("selected-icon");
730        dropdownMenu.classList.toggle("expanded");
731        dropdownMenu.classList.toggle("show");
732    });
733
734    dropdownOptions?.forEach((option) => {
735        option.addEventListener("click", () => {
736            const iconHTML = dropdownButton.querySelector("i").outerHTML;
737            const anchorElement = option.querySelector("li a");
738
739            dropdownButton.innerHTML = `${anchorElement.textContent} ${iconHTML}`;
740
741            // const anchorElement = option.querySelector("li a");
742            // dropdownButton.innerText = anchorElement.textContent;
743
744            dropdownButton.classList.add("selected-option");
745            dropdownMenu.classList.remove("expanded");
746        });
747    });
748
749    // Close the menu when clicking outside
750    document.addEventListener("click", (event) => {
751        if (
752            !dropdownButton?.contains(event?.target) &&
753            !dropdownMenu?.contains(event?.target)
754        ) {
755            if (answers.Items[1].Answers.length > 0) {
756                nextButton2.classList.add("activate-button");
757                nextButton2.disabled = false;
758            }
759            dropdownMenu?.classList?.remove("show");
760        }
761    });
762
763    // Add click event listeners to the menu items
764    const menuItems = dropdownMenu?.querySelectorAll("li");
765
766    menuItems?.forEach((menuItem) => {
767        menuItem.addEventListener("click", (event) => {
768            // Log the selected option
769            answers.Items[1].Answers = [];
770            answers.Items[1].Answers.push(menuItem.textContent.trim());
771            question2Input.nodeValue = answers.Items[1].Answers.join("|");
772            question2Input.value = answers.Items[1].Answers.join("|");
773
774            nextButton2.classList.add("activate-button");
775            nextButton2.disabled = false;
776
777            event.stopPropagation();
778
779            // Close the menu
780            dropdownMenu.classList.remove("show");
781            // Prevent the click event from propagating further
782        });
783    });
784
785    // CONTROLS FOR QUESTION 3
786    const question3 = document.querySelectorAll(".question-3-option");
787    const greyCircles = document.querySelectorAll(".grey-circle-prio");
788    const redText = document.querySelectorAll(".red-text");
789    let selectedCount = 0;
790    let textPriority = ["Highest priority", "Medium priority", "Lowest priority"];
791    let answer3 = [];
792
793    question3.forEach((ques, index) => {
794        ques.addEventListener("click", () => {
795            console.log(answers?.Items[2]?.Answers);
796            console.log(answers?.Items[2]?.Answers[0]?.length);
797
798            if (answers?.Items[2]?.Answers[0]?.length === 2) {
799                nextButton3.classList.add("activate-button");
800                nextButton3.disabled = false;
801            } else {
802                nextButton3.classList.remove("activate-button");
803                nextButton3.disabled = true;
804            }
805
806            ques.classList.toggle("selected");
807
808            // Toggle the class 'selected-priority' on the corresponding grey-circle element
809            greyCircles[index].classList.toggle("selected-priority");
810            redText[index].textContent = textPriority[selectedCount];
811            const isSelected = ques.classList.contains("selected");
812
813            // If it's selected, add the answer to the array
814            if (isSelected && answers.Items[2].Answers.length !== 3) {
815                answer3.push(ques.querySelector(".text").textContent.trim());
816            } else {
817                // If it's deselected, remove the answer from the array
818
819                const answerIndex = answer3.indexOf(
820                    ques.querySelector(".text").textContent
821                );
822
823                if (answerIndex !== -1) {
824                    answer3.splice(answerIndex, 1);
825                }
826
827                if (answers.Items[2].Answers.length >= 1) {
828                    question3.forEach((item, itemIndex) => {
829                        if (itemIndex !== index) {
830                            item.classList.toggle("selected", false);
831                        }
832                    });
833
834                    greyCircles.forEach((item, index) => {
835                        item.classList.toggle("selected-priority", false);
836                        item.textContent = null;
837                    });
838
839                    redText.forEach((item, index) => {
840                        item.textContent = null;
841                    });
842
843                    answer3.length = 0;
844                    selectedCount = 1;
845                }
846            }
847            answers.Items[2].Answers = [];
848            answers.Items[2].Answers.push(answer3);
849            const pipeSeparatedString = answer3.join("|");
850            question3Input.nodeValue = pipeSeparatedString;
851            question3Input.value = pipeSeparatedString;
852
853            // Update the text content of the grey-circle to the order of selection
854            if (ques.classList.contains("selected")) {
855                selectedCount++;
856                greyCircles[index].textContent = selectedCount;
857            } else {
858                selectedCount--;
859                greyCircles[index].textContent = "";
860                redText[index].textContent = "";
861            }
862        });
863    });
864
865    // CONTROLS FOR QUESTION 4
866    const question4 = document.querySelectorAll(".question-4-option");
867    let answer4 = [];
868
869    question4.forEach((ques, index) => {
870        ques.addEventListener("click", () => {
871            const greyCircle2 = ques.querySelector(".grey-circle");
872            console.log(ques);
873            const tick = ques.querySelector("#tick");
874
875            // console.log(tick)
876
877            ques.classList.toggle("selected");
878            greyCircle2.classList.toggle("selected-red-circle");
879            tick?.classList.toggle("show-icon");
880
881            // console.log(tick);
882
883            // Check if the card is selected or not
884            const isSelected = ques.classList.contains("selected");
885
886            // If it's selected, add the answer to the array
887            if (isSelected) {
888                answer4.push(ques.querySelector(".text").textContent.trim());
889            } else {
890                // If it's deselected, remove the answer from the array
891                const answerIndex = answer4.indexOf(
892                    ques.querySelector(".text").textContent
893                );
894                if (answerIndex !== -1) {
895                    answer4.splice(answerIndex, 1);
896                }
897            }
898
899            answers.Items[3].Answers = [];
900            answers.Items[3].Answers.push(answer4);
901            question4Input.nodeValue = answers.Items[3].Answers.join("|");
902            question4Input.value = answers.Items[3].Answers.join("|");
903            console.log(answers);
904
905            if (answers?.Items[3]?.Answers[0]?.length > 0) {
906                nextButton4.classList.add("activate-button");
907                nextButton4.disabled = false;
908            } else {
909                nextButton4.classList.remove("activate-button");
910                nextButton4.disabled = true;
911            }
912        });
913    });
914
915    // CONTROLS FOR QUESTION 5
916    const question5 = document.querySelectorAll(".question-5-option");
917    question5.forEach((ques) => {
918        ques.addEventListener("click", () => {
919            // Check if there is a previously selected option
920            if (selectedOption) {
921                selectedOption.classList.remove("selected");
922            }
923
924            ques.classList.add("selected");
925            selectedOption = ques;
926
927            const optionText = ques.querySelector(".text").textContent.trim();
928            answers.Items[4].Answers = [];
929            answers.Items[4].Answers.push(optionText);
930            question5Input.nodeValue = optionText;
931            question5Input.value = optionText;
932            console.log(answers);
933
934            if (answers.Items[4].Answers.length > 0) {
935                nextButton5.classList.add("activate-button");
936                nextButton5.disabled = false;
937            }
938        });
939    });
940
941    // CONTROLS FOR QUESTION 6
942    const question6 = document.querySelectorAll(".question-6-option");
943    question6.forEach((ques) => {
944        ques.addEventListener("click", () => {
945            // Check if there is a previously selected option
946            if (selectedOption) {
947                selectedOption.classList.remove("selected");
948            }
949
950            ques.classList.add("selected");
951            selectedOption = ques;
952
953            const optionText = ques.querySelector(".text").textContent.trim();
954            answers.Items[5].Answers = [];
955            answers.Items[5].Answers.push(optionText);
956            question6Input.nodeValue = optionText;
957            question6Input.value = optionText;
958            console.log(answers);
959
960            if (answers.Items[5].Answers.length > 0) {
961                nextButton6.classList.add("activate-button");
962                nextButton6.disabled = false;
963            }
964        });
965    });
966
967    // CONTROLS FOR QUESTION 7
968    const question7 = document.querySelectorAll(".question-7-option");
969    question7.forEach((ques) => {
970        ques.addEventListener("click", () => {
971            // Check if there is a previously selected option
972            if (selectedOption) {
973                selectedOption.classList.remove("selected");
974            }
975
976            ques.classList.add("selected");
977            selectedOption = ques;
978
979            const optionText = ques.querySelector(".text").textContent.trim();
980            answers.Items[6].Answers = [];
981            answers.Items[6].Answers.push(optionText);
982            question7Input.nodeValue = answers.Items[6].Answers.join("|");
983            question7Input.value = answers.Items[6].Answers.join("|");
984            console.log(answers);
985
986            if (answers.Items[6].Answers.length > 0) {
987                nextButton7.classList.add("activate-button");
988                nextButton7.disabled = false;
989            }
990        });
991    });
992
993    const questionContainers = [
994        document.getElementById("question-1"),
995        document.getElementById("question-2"),
996        document.getElementById("question-3"),
997        document.getElementById("question-4"),
998        document.getElementById("question-5"),
999        document.getElementById("question-6"),
1000        document.getElementById("question-7"),
1001        document.getElementById("question-8"),
1002        document.getElementById("progress-bar"),
1003        // Add more question containers here as needed
1004    ];
1005
1006    // Initialize the current question index
1007    let currentQuestionIndex = 0;
1008
1009    // Function to show the current question and hide the others
1010    function showCurrentQuestion() {
1011        questionContainers.map((container, index) => {
1012            if (index === currentQuestionIndex) {
1013                if (container?.style) {
1014                    container.style.display = "flex";
1015                }
1016            } else {
1017                if (container?.style) {
1018                    container.style.display = "none";
1019                }
1020            }
1021        });
1022    }
1023
1024    // Overlay
1025    const darkOverlay = document.querySelector(".dark-overlay");
1026    const whiteOverlay = document.getElementById("white-overlay");
1027
1028    // Background Images
1029    const firstImage = document.getElementById("first-image");
1030    const secondImage = document.getElementById("second-image");
1031
1032    // Quiz
1033    const quizContainer = document.getElementById("all-question");
1034
1035    // Moving Assets
1036    const plane = document.getElementById("plane");
1037    const cloudBed = document.getElementById("cloud-bed");
1038
1039    const cloudOne = document.getElementById("cloud-one");
1040    const cloudTwo = document.getElementById("cloud-two");
1041    const cloudThree = document.getElementById("cloud-three");
1042
1043    const bikerImage = document.getElementById("biker-image");
1044    const boatImage = document.getElementById("boat-image");
1045
1046    // Loading bar
1047    const loadingBar = document.getElementById("loading-white-bar");
1048    const resultLoadingBar = document.getElementById("results-loading");
1049
1050    if (loadingBar && loadingBar.style) {
1051        loadingBar.style.width = "0%";
1052    }
1053
1054    // Animate in
1055    setTimeout(() => {
1056        firstImage?.classList.remove("pre-load");
1057    }, 200);
1058
1059    setTimeout(() => {
1060        secondImage?.classList.remove("pre-load");
1061        firstImage?.classList.add("move-up-delay");
1062    }, 1800);
1063
1064    // Start the quiz after 2 seconds
1065
1066    setTimeout(() => {
1067        if (loadingBar && loadingBar.style) {
1068            loadingBar.style.width = "12.5%";
1069        }
1070        quizContainer?.classList?.replace("hide", "show");
1071        bikerImage?.classList.replace("hide", "show");
1072        firstImage?.classList.add("blurred");
1073        secondImage?.classList.add("blurred");
1074        bikerImage?.classList.add("blurred");
1075    }, 4000);
1076
1077    // Initially, show the first question
1078    showCurrentQuestion();
1079
1080    // Get references to the "Next" and "Back" buttons by their IDs
1081    const nextButton1 = document.getElementById("next-button-1");
1082    const backButton1 = document.getElementById("back-button-1");
1083
1084    const nextButton2 = document.getElementById("next-button-2");
1085    const backButton2 = document.getElementById("back-button-2");
1086
1087    const nextButton3 = document.getElementById("next-button-3");
1088    const backButton3 = document.getElementById("back-button-3");
1089
1090    const nextButton4 = document.getElementById("next-button-4");
1091    const backButton4 = document.getElementById("back-button-4");
1092
1093    const nextButton5 = document.getElementById("next-button-5");
1094    const backButton5 = document.getElementById("back-button-5");
1095
1096    const nextButton6 = document.getElementById("next-button-6");
1097    const backButton6 = document.getElementById("back-button-6");
1098
1099    const nextButton7 = document.getElementById("next-button-7");
1100    const backButton7 = document.getElementById("back-button-7");
1101
1102    const nextButton8 = document.querySelector(".TPE-QuizSubmissionButton");
1103    const skipButton8 = document.querySelector(".TPE-Quiz-Skip-Btn");
1104
1105    nextButton1?.addEventListener("click", () => {
1106        if (currentQuestionIndex < questionContainers.length - 1) {
1107            currentQuestionIndex++;
1108            showCurrentQuestion();
1109            loadingBar.style.width = "25%";
1110        }
1111    });
1112
1113    backButton1?.addEventListener("click", () => {
1114        if (currentQuestionIndex > 0) {
1115            currentQuestionIndex--;
1116            showCurrentQuestion();
1117        }
1118    });
1119
1120    nextButton2?.addEventListener("click", () => {
1121        firstImage.classList.remove("move-slow");
1122        secondImage.classList.remove("move-fast");
1123
1124        if (currentQuestionIndex < questionContainers.length - 1) {
1125            currentQuestionIndex++;
1126
1127            quizContainer.classList.replace("show", "hide");
1128            firstImage.classList.remove("blurred");
1129            secondImage.classList.remove("blurred");
1130            bikerImage.classList.remove("blurred");
1131            bikerImage.classList.add("move-down");
1132            loadingBar.style.width = "25%";
1133
1134            setTimeout(() => {
1135                firstImage.classList.replace("initial", "move-down");
1136                secondImage.classList.replace("initial", "move-down");
1137
1138                showCurrentQuestion();
1139                setTimeout(() => {
1140                    quizContainer.classList.replace("hide", "show");
1141                    boatImage.classList.replace("disappears", "appears");
1142                    firstImage.classList.add("blurred");
1143                    secondImage.classList.add("blurred");
1144                    boatImage.classList.add("blurred");
1145
1146                    loadingBar.style.width = "37.5%";
1147                }, 2000);
1148            }, 1300);
1149        }
1150    });
1151
1152    backButton2?.addEventListener("click", () => {
1153        if (currentQuestionIndex > 0) {
1154            currentQuestionIndex--;
1155            showCurrentQuestion();
1156            loadingBar.style.width = "12.5%";
1157        }
1158    });
1159
1160    nextButton3?.addEventListener("click", () => {
1161        loadingBar.style.width = "50%";
1162        if (currentQuestionIndex < questionContainers.length - 1) {
1163            currentQuestionIndex++;
1164            showCurrentQuestion();
1165        }
1166    });
1167
1168    backButton3?.addEventListener("click", () => {
1169        if (currentQuestionIndex > 0) {
1170            currentQuestionIndex--;
1171        }
1172
1173        firstImage.classList.add("move-slow");
1174        secondImage.classList.add("move-fast");
1175        quizContainer.classList.replace("show", "hide");
1176        firstImage.classList.remove("blurred");
1177        secondImage.classList.remove("blurred");
1178        boatImage.classList.remove("blurred");
1179
1180        setTimeout(() => {
1181            firstImage.classList.replace("move-down", "initial");
1182            secondImage.classList.replace("move-down", "initial");
1183            boatImage.classList.replace("appears", "disappears");
1184
1185            showCurrentQuestion();
1186            setTimeout(() => {
1187                quizContainer.classList.replace("hide", "show");
1188                firstImage.classList.add("blurred");
1189                secondImage.classList.add("blurred");
1190                bikerImage.classList.add("blurred");
1191                bikerImage.classList.remove("move-down");
1192                loadingBar.style.width = "25%";
1193            }, 2000);
1194        }, 1000);
1195    });
1196
1197    nextButton4?.addEventListener("click", () => {
1198        if (currentQuestionIndex < questionContainers.length - 1) {
1199            currentQuestionIndex++;
1200        }
1201
1202        quizContainer.classList.replace("show", "hide");
1203        firstImage.classList.remove("blurred");
1204
1205        cloudOne.classList.remove("disappears");
1206        cloudOne.classList.remove("disappears-up");
1207        cloudTwo.classList.remove("disappears");
1208        cloudTwo.classList.remove("disappears-up");
1209        cloudThree.classList.remove("disappears");
1210        cloudThree.classList.remove("disappears-up");
1211        cloudOne.classList.add("blurred-xl");
1212        cloudTwo.classList.add("blurred-xs");
1213        cloudThree.classList.add("blurred");
1214
1215        boatImage.classList.remove("blurred");
1216        boatImage.classList.replace("appears", "disappears");
1217
1218        setTimeout(() => {
1219            firstImage.classList.replace("move-down", "move-down-sky");
1220            setTimeout(() => {
1221                cloudOne.classList.add("appears");
1222            }, 100);
1223
1224            setTimeout(() => {
1225                cloudTwo.classList.add("appears");
1226            }, 300);
1227
1228            setTimeout(() => {
1229                cloudThree.classList.add("appears");
1230            }, 500);
1231            showCurrentQuestion();
1232            setTimeout(() => {
1233                quizContainer.classList.replace("hide", "show");
1234                firstImage.classList.add("blurred");
1235                loadingBar.style.width = "62.5%";
1236            }, 2000);
1237        }, 1000);
1238    });
1239
1240    backButton4?.addEventListener("click", () => {
1241        if (currentQuestionIndex > 0) {
1242            currentQuestionIndex--;
1243            showCurrentQuestion();
1244            loadingBar.style.width = "37.5%";
1245        }
1246    });
1247
1248    nextButton5?.addEventListener("click", () => {
1249        if (currentQuestionIndex < questionContainers.length - 1) {
1250            currentQuestionIndex++;
1251            showCurrentQuestion();
1252            loadingBar.style.width = "75%";
1253        }
1254    });
1255
1256    backButton5?.addEventListener("click", () => {
1257        if (currentQuestionIndex > 0) {
1258            currentQuestionIndex--;
1259        }
1260
1261        quizContainer.classList.replace("show", "hide");
1262        firstImage.classList.remove("blurred");
1263
1264        setTimeout(() => {
1265            firstImage.classList.replace("move-down-sky", "move-down");
1266            cloudOne.classList.replace("appears", "disappears-up");
1267            cloudTwo.classList.replace("appears", "disappears-up");
1268            cloudThree.classList.replace("appears", "disappears-up");
1269
1270            showCurrentQuestion();
1271            setTimeout(() => {
1272                boatImage.classList.replace("disappears", "appears");
1273                quizContainer.classList.replace("hide", "show");
1274                firstImage.classList.add("blurred");
1275                boatImage.classList.add("blurred");
1276                loadingBar.style.width = "50%";
1277            }, 2000);
1278        }, 1000);
1279    });
1280
1281    nextButton6?.addEventListener("click", () => {
1282        if (currentQuestionIndex < questionContainers.length - 1) {
1283            currentQuestionIndex++;
1284        }
1285
1286        quizContainer.classList.replace("show", "hide");
1287        firstImage.classList.remove("blurred");
1288        secondImage.classList.remove("blurred");
1289        cloudBed.classList.remove("disappears");
1290        plane.classList.remove("disappears");
1291
1292        plane.classList.add("appears");
1293        cloudOne.classList.replace("appears", "disappears");
1294        cloudTwo.classList.replace("appears", "disappears");
1295        cloudThree.classList.replace("appears", "disappears");
1296
1297        setTimeout(() => {
1298            firstImage.classList.replace("move-down-sky", "move-down-plane");
1299            cloudBed.classList.add("appears");
1300
1301            showCurrentQuestion();
1302            setTimeout(() => {
1303                quizContainer.classList.replace("hide", "show");
1304                firstImage.classList.add("blurred");
1305                secondImage.classList.add("blurred");
1306                cloudBed.classList.add("blurred");
1307                plane.classList.add("blurred");
1308                loadingBar.style.width = "87.5%";
1309            }, 3000);
1310        }, 1000);
1311    });
1312
1313    backButton6?.addEventListener("click", () => {
1314        if (currentQuestionIndex > 0) {
1315            currentQuestionIndex--;
1316            showCurrentQuestion();
1317            loadingBar.style.width = "62.5%";
1318        }
1319    });
1320
1321    backButton7?.addEventListener("click", () => {
1322        if (currentQuestionIndex > 0) {
1323            currentQuestionIndex--;
1324        }
1325
1326        quizContainer.classList.replace("show", "hide");
1327        firstImage.classList.remove("blurred");
1328
1329        cloudBed.classList.remove("blurred");
1330        plane.classList.remove("blurred");
1331
1332        setTimeout(() => {
1333            firstImage.classList.replace("move-down-plane", "move-down-sky");
1334
1335            setTimeout(() => {
1336                cloudOne.classList.replace("disappears", "appears");
1337                cloudTwo.classList.replace("disappears", "appears");
1338                cloudThree.classList.replace("disappears", "appears");
1339            }, 1000);
1340
1341            cloudBed.classList.replace("appears", "disappears");
1342            plane.classList.replace("appears", "disappears");
1343
1344            showCurrentQuestion();
1345            setTimeout(() => {
1346                quizContainer.classList.replace("hide", "show");
1347                firstImage.classList.add("blurred");
1348
1349                cloudOne.classList.add("blurred-xl");
1350                cloudTwo.classList.add("blurred-xs");
1351                cloudThree.classList.add("blurred");
1352                loadingBar.style.width = "75%";
1353            }, 2000);
1354        }, 1000);
1355    });
1356
1357    nextButton7?.addEventListener("click", () => {
1358        if (currentQuestionIndex < questionContainers.length - 1) {
1359            currentQuestionIndex++;
1360            showCurrentQuestion();
1361        }
1362        loadingBar.style.width = "100%";
1363    });
1364
1365    nextButton8?.addEventListener("click", () => {
1366        let flag = validateForm();
1367
1368        if (flag) {
1369            if (currentQuestionIndex < questionContainers.length - 1) {
1370                currentQuestionIndex++;
1371                showCurrentQuestion();
1372            }
1373
1374            setTimeout(() => {
1375                resultLoadingBar.classList.replace(
1376                    "loading-bar-white",
1377                    "loading-bar-white-3"
1378                );
1379            }, 0);
1380        }
1381    });
1382
1383    skipButton8?.addEventListener("click", () => {
1384        if (currentQuestionIndex < questionContainers.length - 1) {
1385            currentQuestionIndex++;
1386            showCurrentQuestion();
1387        }
1388
1389        setTimeout(() => {
1390            resultLoadingBar.classList.replace(
1391                "loading-bar-white",
1392                "loading-bar-white-3"
1393            );
1394        }, 0);
1395    });
1396
1397    function validateForm() {
1398        var name = document?.querySelectorAll('input[data-sc-field-name="name"]')[0]
1399            ?.value;
1400        var company = document?.querySelectorAll(
1401            'input[data-sc-field-name="company"]'
1402        )[0]?.value;
1403        var designation = document?.querySelectorAll(
1404            'input[data-sc-field-name="designation"]'
1405        )[0]?.value;
1406        var email = document?.querySelectorAll(
1407            'input[data-sc-field-name="email"]'
1408        )[0]?.value;
1409        var Checkbox = document
1410            ?.querySelectorAll('input[data-sc-field-name="Checkbox"]')[0]
1411            ?.getAttribute("isCheck");
1412        var EmailValidationClass = document
1413            ?.querySelectorAll('input[data-sc-field-name="email"]')[0]
1414            ?.getAttribute("class");
1415        var FocusSelectElement = document?.querySelector(
1416            'select[data-sc-field-name="Focus"]'
1417        )?.value;
1418
1419        if (
1420            name !== "" &&
1421            company !== "" &&
1422            designation !== "" &&
1423            FocusSelectElement != "default" &&
1424            email !== "" &&
1425            EmailValidationClass === "qna-input valid" &&
1426            Checkbox === "true"
1427        ) {
1428            return true;
1429        } else {
1430            return false;
1431        }
1432    }
1433    const checkElement = document.querySelectorAll(
1434        'input[data-sc-field-name="Checkbox"]'
1435    )[0];
1436    checkElement?.addEventListener("click", function (event) {
1437        // alert("hi");
1438        if (checkElement.hasAttribute("isCheck")) {
1439            if (checkElement.getAttribute("isCheck") === "false") {
1440                checkElement.setAttribute("isCheck", "true");
1441            } else {
1442                checkElement.setAttribute("isCheck", "false");
1443            }
1444        } else {
1445            checkElement.setAttribute("isCheck", "true");
1446        }
1447    });
1448
1449    document.addEventListener("click", function (event) {
1450        let flag = validateForm();
1451        if (flag) {
1452            nextButton8?.classList.add("activate-button");
1453        } else {
1454            nextButton8?.classList?.remove("activate-button");
1455        }
1456    });
1457
1458    document.addEventListener("keydown", function (event) {
1459        let flag = validateForm();
1460        if (flag) {
1461            nextButton8?.classList.add("activate-button");
1462        } else {
1463            nextButton8?.classList.remove("activate-button");
1464        }
1465    });
1466
1467    document
1468        ?.getElementsByTagName("form")[0]
1469        ?.addEventListener("keydown", function (event) {
1470            if (event.key === "Enter") {
1471                if (!nextButton8?.classList?.contains("activate-button")) {
1472                    event.preventDefault(); // Prevent the Enter key press from submitting the form
1473                } else {
1474                    nextButton8.click();
1475                }
1476            }
1477        });
1478
1479    const tpeLogo = document.getElementById("tpe-logo");
1480
1481    // redirect to homepage on logo click
1482    if (tpeLogo) {
1483        tpeLogo?.addEventListener("click", function () {
1484            console.log("testing");
1485        });
1486    }
1487}
1488
1489function blockRedirection() {
1490    const elements = document.querySelectorAll(".block-href");
1491
1492    elements.forEach(function (element) {
1493        element.addEventListener("click", function (event) {
1494            event.preventDefault();
1495        });
1496    });
1497}
1498
1499// For UFSE double filters + query strings
1500// This is specifically for showing the red tick when checking the checkboxes
1501function nestedFilterAction() {
1502    // This is for expanding the filter
1503    const toggleIcons = document.querySelectorAll(".toggle-icon");
1504    toggleIcons.forEach(function (toggleIcon) {
1505        toggleIcon.addEventListener("click", function () {
1506            const nestedFilters = toggleIcon
1507                .closest(".nested-filter-li")
1508                .querySelector(".nested-filters");
1509            if (nestedFilters?.style?.maxHeight) {
1510                nestedFilters.style.paddingTop = "0px";
1511                nestedFilters.style.maxHeight = null;
1512                toggleIcon.classList.remove("ri-subtract-line");
1513                toggleIcon.classList.add("ri-add-line");
1514            } else {
1515                nestedFilters.style.paddingTop = "20px";
1516                nestedFilters.style.maxHeight = "1000px";
1517                toggleIcon.classList.remove("ri-add-line");
1518                toggleIcon.classList.add("ri-subtract-line");
1519            }
1520        });
1521    });
1522}
1523
1524// For UFSE file uploads in build your profile form
1525function fileUpload() {
1526    document.addEventListener("DOMContentLoaded", function () {
1527        var fileUploadGroups = document.querySelectorAll(".file-upload-group");
1528        fileUploadGroups.forEach(function (group) {
1529            var fileInput = group.querySelector(".file-input");
1530            var uploadFileContainer = group.querySelector(".upload-file-container");
1531            var allFiles = [];
1532
1533            fileInput.addEventListener("change", function () {
1534                var maxFileCount = parseInt(
1535                    this.getAttribute("data-val-filecount-max"),
1536                    10
1537                );
1538                var newFiles = Array.from(this.files);
1539
1540                if (maxFileCount === 1) {
1541                    // If max file count is 1, replace the existing file
1542                    allFiles = newFiles;
1543                } else {
1544                    // Append new files to the existing ones
1545                    newFiles.forEach((file) => {
1546                        if (!allFiles.some((f) => f.name === file.name)) {
1547                            allFiles.push(file);
1548                        }
1549                    });
1550                }
1551
1552                resetAndRepopulateInput(fileInput, allFiles);
1553                updateUploadedFilesDisplay(uploadFileContainer, allFiles, fileInput);
1554            });
1555        });
1556
1557        // This is to show the uploaded file at the bottom of the file input
1558        function updateUploadedFilesDisplay(container, files, input) {
1559            container.innerHTML = "";
1560            files.forEach(function (file, index) {
1561                var uploadedFileDiv = document.createElement("div");
1562                uploadedFileDiv.className = "uploaded-file";
1563
1564                var textContainerDiv = document.createElement("div");
1565                textContainerDiv.className = "text-container";
1566
1567                var icon = document.createElement("i");
1568                icon.className = "ri-file-text-line icon";
1569                textContainerDiv.appendChild(icon);
1570
1571                var fileNameParagraph = document.createElement("p");
1572                fileNameParagraph.textContent = file.name;
1573                textContainerDiv.appendChild(fileNameParagraph);
1574
1575                uploadedFileDiv.appendChild(textContainerDiv);
1576
1577                var removeText = document.createElement("p");
1578                removeText.className = "remove-text";
1579                removeText.textContent = "Remove";
1580                removeText.style.cursor = "pointer";
1581                if (input.id == 'fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_d0ffac70-d85e-469f-867d-20c899265b87__Files') {
1582                    removeText.setAttribute("type", "profile-picture");
1583                }
1584                removeText.onclick = function () {
1585                    files.splice(index, 1);
1586                    resetAndRepopulateInput(input, files);
1587                    updateUploadedFilesDisplay(container, files, input);
1588                };
1589                uploadedFileDiv.appendChild(removeText);
1590
1591                container.appendChild(uploadedFileDiv);
1592            });
1593
1594            // Update the margin based on the number of files
1595            if (files.length > 0) {
1596                container.style.marginBottom = "24px";
1597            } else {
1598                container.style.marginBottom = "0";
1599            }
1600        }
1601
1602        // When user click cancel without uploading any files, the exsiting file wont be deleted
1603        function resetAndRepopulateInput(input, files) {
1604            var dataTransfer = new DataTransfer();
1605            files.forEach((file) => dataTransfer.items.add(file));
1606            input.files = dataTransfer.files;
1607        }
1608    });
1609}
1610
1611(function ($, window, undefined) {
1612    "use strict";
1613
1614    $(".slider-button .item").on("click", function (e) {
1615        $(this).siblings().removeClass("active");
1616        $(this).addClass("active");
1617    });
1618
1619    inpageNav();
1620    checkUserAgent();
1621    alphabetFilter();
1622    glossaryFilter();
1623    videoCarousel();
1624    openChatBot();
1625    formValidation();
1626    fancyBoxRendering();
1627    coveoRendering();
1628    closeAnnouncement();
1629    compassAnimation();
1630    tpeQuizLogic();
1631    blockRedirection();
1632    nestedFilterAction();
1633    fileUpload();
1634
1635    if ($("[data-autocomplete]").length > 0) {
1636        searchAutoComplete($("[data-autocomplete]"));
1637    }
1638
1639    if ($(window).width() > 991) {
1640        $(window).on("scroll", function () {
1641            if (
1642                $(".navbar.navbar-expand-lg .nav-item .dropdown-toggle").hasClass(
1643                    "show"
1644                )
1645            ) {
1646                $(
1647                    ".navbar.navbar-expand-lg .nav-item .dropdown-toggle.show"
1648                )[0].click();
1649            }
1650        });
1651    }
1652    if ($(window).width() <= 576) {
1653        $(".nav-link.dropdown-toggle").on("click", function () {
1654            var spaceToScroll =
1655                $(this).closest("li").index() * $(this).innerHeight() + 2;
1656            if ($(this).position().top > 16) {
1657                $(".navbar-collapse").animate({ scrollTop: spaceToScroll }, 300);
1658            }
1659        });
1660    }
1661    if ($(window).width() < 992) {
1662        $(".nav-item > .navbar-toggler").on("click", function () {
1663            if ($(".nav-item > .navbar-toggler").attr("aria-expanded") == "false") {
1664                $(".navbar-expand-lg").attr("showing", false);
1665                $("body").removeClass("nav-opening");
1666            } else {
1667                $(".navbar-expand-lg").attr("showing", true);
1668                $("body").addClass("nav-opening");
1669            }
1670        });
1671        $("#dropdownUserMb").on("click", function () {
1672            $(".navbar-expand-lg").attr("showing", true);
1673            if (
1674                $(".nav-item > .navbar-toggler[data-bs-toggle]").attr(
1675                    "aria-expanded"
1676                ) == "true"
1677            ) {
1678                $("#navbar-content").removeClass("show");
1679                $(".nav-item > .navbar-toggler[data-bs-toggle]")
1680                    .attr("aria-expanded", false)
1681                    .addClass("collapsed");
1682            }
1683        });
1684    }
1685    // resize screen and change position of hero carousel banner
1686    const carouselIndicatorPos = function (heroBannerCarousel) {
1687        var imageHeight = heroBannerCarousel.find(".image").height() + 24;
1688        var carouselIndicator = heroBannerCarousel.find(".slider-control-bar");
1689        carouselIndicator.css({ top: imageHeight });
1690        if ($(window).width() < 992) {
1691            imageHeight = heroBannerCarousel.find(".image").height() + 24;
1692            if ($(window).width() < 577) {
1693                imageHeight = imageHeight - 8;
1694            }
1695            carouselIndicator.css({ top: imageHeight });
1696        } else {
1697            carouselIndicator.css({ top: "" });
1698        }
1699    };
1700    var heroBannerCarousel = $(".hero-banner-carousel");
1701    if (heroBannerCarousel.length > 0) {
1702        heroBannerCarousel
1703            .find(".carousel-indicators .item:first-child")
1704            .addClass("active");
1705    }
1706
1707    var newsCarousel = $(".singleCarousel");
1708    if (newsCarousel.length > 0) {
1709        var totalSlide = newsCarousel.find(".carousel-item").length;
1710        newsCarousel.find(".slider-total").text(totalSlide);
1711        newsCarousel.on("slid.bs.carousel", function () {
1712            var carouselData = $(this).find(".carousel-item.active");
1713            var currentIndex = carouselData.index();
1714            console.log(currentIndex);
1715            newsCarousel.find(".slider-index").text(currentIndex + 1);
1716        });
1717    }
1718    var autoScrollCarousel = $(".auto-scroll-carousel .slider");
1719    if (autoScrollCarousel.length > 0) {
1720        autoScrollCarousel.slick({
1721            slidesToShow: 5,
1722            slidesToScroll: 5,
1723            autoplay: true,
1724            autoplaySpeed: 2000,
1725            arrows: true,
1726            infinite: true,
1727            dots: true,
1728            responsive: [
1729                {
1730                    breakpoint: 576,
1731                    settings: {
1732                        slidesToShow: 3,
1733                        slidesToScroll: 3,
1734                    },
1735                },
1736            ],
1737        });
1738    }
1739
1740    var enterpriseCarousel = $(".enterprise-carousel .slider");
1741    if (enterpriseCarousel.length > 0 && $(window).width() > 1141) {
1742        enterpriseCarousel.slick({
1743            slidesToShow: 3.5,
1744            slidesToScroll: 1,
1745            arrows: true,
1746            variableWidth: true,
1747            dots: false,
1748            infinite: false,
1749        });
1750    }
1751
1752    var exclusiveDealsCarousel = $(".exclusive-deals-carousel .slider");
1753    if (exclusiveDealsCarousel.length > 0) {
1754        exclusiveDealsCarousel.slick({
1755            slidesToShow: 1,
1756            slidesToScroll: 1,
1757            variableWidth: true,
1758            infinite: false,
1759            dots: true,
1760            appendDots: $(".deals-carousel-navigation-container"),
1761            useTransform: false,
1762            responsive: [
1763                {
1764                    breakpoint: 1025,
1765                    settings: {
1766                        infinite: false,
1767                        arrows: false,
1768                        dots: true,
1769                        autoplay: true,
1770                        autoplaySpeed: 3000,
1771                        touchThreshold: 1000,
1772                        swipeToSlide: false,
1773                        cssEase: "linear",
1774                    },
1775                },
1776            ],
1777        });
1778    }
1779
1780    var $copyUrl = $(".share-icon.copy-url");
1781    if ($copyUrl.length > 0) {
1782        var $url = $(location).attr("href");
1783        var dummy = document.createElement("input");
1784        $copyUrl.on("click", function () {
1785            document.body.appendChild(dummy);
1786            dummy.value = $url;
1787            dummy.select();
1788            document.execCommand("copy");
1789            document.body.removeChild(dummy);
1790            $copyUrl.find(".confirmed-copied").addClass("copied");
1791            setTimeout(() => {
1792                $copyUrl.find(".confirmed-copied").removeClass("copied");
1793            }, 1000);
1794        });
1795    }
1796
1797    $(".invite-link-wrapper .copy-url").on("click", function () {
1798        var $url = $(this).siblings(".invite-link").text();
1799        var dummy = document.createElement("input");
1800        document.body.appendChild(dummy);
1801        dummy.value = $url;
1802        dummy.select();
1803        document.execCommand("copy");
1804        document.body.removeChild(dummy);
1805        $(this).find(".confirmed-copied").addClass("copied");
1806        setTimeout(() => {
1807            $(this).find(".confirmed-copied").removeClass("copied");
1808        }, 1000);
1809    });
1810
1811    $(".referral-code-wrapper .copy-url").on("click", function () {
1812        var $url = $(this).siblings(".referral-code").text();
1813        var dummy = document.createElement("input");
1814        document.body.appendChild(dummy);
1815        dummy.value = $url;
1816        dummy.select();
1817        document.execCommand("copy");
1818        document.body.removeChild(dummy);
1819        $(this).find(".confirmed-copied").addClass("copied");
1820        setTimeout(() => {
1821            $(this).find(".confirmed-copied").removeClass("copied");
1822        }, 1000);
1823    });
1824
1825    if ($(".vertical-tabs").length > 0) {
1826        var hash = location.hash.replace(/^#/, "");
1827        if (hash) {
1828            var triggerEl = document.querySelector("#" + hash + "-tab");
1829            triggerEl.click();
1830        }
1831    }
1832
1833    $(function () {
1834        const sharingSection = $("#sharing-section");
1835        const socialSharing = $("#social-sharing");
1836        if (socialSharing.length > 0 && sharingSection.length > 0) {
1837            var top = sharingSection.offset().top;
1838            var bottom = sharingSection.innerHeight() + top - 200;
1839            $(window).on("scroll", function () {
1840                if ($(window).scrollTop() > top && $(window).scrollTop() < bottom) {
1841                    socialSharing.attr("sticky", true);
1842                } else {
1843                    socialSharing.attr("sticky", false);
1844                }
1845            });
1846        }
1847    });
1848    $(function () {
1849        const eventRegister = $(".event-register");
1850        if (eventRegister.length > 0) {
1851            var top = eventRegister.offset().top;
1852            var bottom =
1853                eventRegister.closest(".editor-wrapper").next().offset().top + 200;
1854            $(window).on("scroll", function () {
1855                if ($(window).scrollTop() > top && $(window).scrollTop() < bottom) {
1856                    eventRegister.attr("sticky", true);
1857                } else {
1858                    eventRegister.attr("sticky", false);
1859                }
1860            });
1861        }
1862    });
1863    $(function () {
1864        const $carousel = $("#newsCarousel");
1865        if (!$carousel.length) return;
1866        $carousel.find(".active").attr("data-processing", "");
1867        $carousel[0].addEventListener("slid.bs.carousel", function () {
1868            $carousel.find("[data-processing]").removeAttr("data-processing");
1869            $carousel.find(".active").attr("data-processing", "");
1870        });
1871    });
1872
1873    /* ------------------------ Media Carousel Component ------------------------ */
1874    var mediaCarousel = $(".media-carousel");
1875    if (mediaCarousel.length > 0) {
1876        var nextContent = mediaCarousel.find(".next-title");
1877        mediaCarousel.find(".slider-for").slick({
1878            slidesToShow: 1,
1879            slidesToScroll: 1,
1880            pauseOnHover: false,
1881            autoplay: true,
1882            autoplaySpeed: 10000,
1883            infinite: true,
1884            arrows: true,
1885            fade: true,
1886            asNavFor: ".slider-nav",
1887            mobileFirst: true,
1888            adaptiveHeight: true,
1889            responsive: [
1890                {
1891                    breakpoint: 1024,
1892                    settings: {
1893                        adaptiveHeight: false,
1894                    },
1895                },
1896            ],
1897        });
1898        mediaCarousel.find(".slider-nav").slick({
1899            slidesToShow: 3,
1900            slidesToScroll: 3,
1901            asNavFor: ".slider-for",
1902            dots: false,
1903            arrows: false,
1904            infinite: true,
1905            focusOnSelect: true,
1906            variableWidth: true,
1907        });
1908
1909        if (mediaCarousel.find(".slick-initialized").length > 0) {
1910            mediaCarousel
1911                .find(".slider-for .slick-current .progress-bar")
1912                .attr("data-loaded", true);
1913            mediaCarousel
1914                .find(".slider-nav .slick-current")
1915                .attr("data-loaded", true);
1916            $(".slick-current").attr("data-current", true);
1917        }
1918
1919        mediaCarousel.on("afterChange", function (event, slick, currentSlide) {
1920            $(".slick-slide").attr("data-current", false);
1921            $(".slick-current").attr("data-current", true);
1922            mediaCarousel
1923                .find('.slick-current[data-loaded= "true"]')
1924                .attr("data-loaded", false);
1925            const nextSlide =
1926                $(".slick-current").next().length > 0
1927                    ? $(".slick-current").next()
1928                    : $(".slick-current").siblings().filter("[data-slick-index=0]");
1929            nextContent.text(nextSlide.find(".card-title").text());
1930        });
1931    }
1932    /* ------------------------ Start Top Stories Component ------------------------ */
1933    var topStories = $(".top-stories-carousel");
1934    if (topStories.length > 0) {
1935        topStories.find(".slider-for").slick({
1936            slidesToShow: 1,
1937            slidesToScroll: 1,
1938            pauseOnHover: false,
1939            autoplay: true,
1940            autoplaySpeed: 10000,
1941            infinite: true,
1942            arrows: true,
1943            fade: true,
1944            asNavFor: ".slider-nav",
1945            mobileFirst: true,
1946            adaptiveHeight: true,
1947            focusOnSelect: false,
1948            responsive: [
1949                {
1950                    breakpoint: 1024,
1951                    settings: {
1952                        adaptiveHeight: false,
1953                    },
1954                },
1955            ],
1956        });
1957
1958        topStories.find(".slider-nav").slick({
1959            slidesToShow: 4,
1960            slidesToScroll: 1,
1961            asNavFor: ".slider-for",
1962            dots: false,
1963            arrows: false,
1964            infinite: true,
1965            focusOnSelect: true,
1966            vertical: true,
1967            verticalSwiping: true,
1968            draggable: false,
1969            responsive: [
1970                {
1971                    breakpoint: 991,
1972                    settings: {
1973                        vertical: false,
1974                        verticalSwiping: false,
1975                        slidesToShow: 4,
1976                        slidesToScroll: 1,
1977                    },
1978                },
1979                {
1980                    breakpoint: 768,
1981                    settings: {
1982                        vertical: false,
1983                        verticalSwiping: false,
1984                        slidesToShow: 2,
1985                        slidesToScroll: 1,
1986                    },
1987                },
1988            ],
1989        });
1990
1991        // Init
1992        if (topStories.find(".slick-initialized").length > 0) {
1993            topStories
1994                .find(".slider-for .slick-current .progress-bar")
1995                .attr("data-loaded", true);
1996            topStories.find(".slider-nav .slick-current").attr("data-loaded", true);
1997            $(".slick-current").attr("data-current", true);
1998            updateNavSlides(0);
1999            $(".slider-for").slick("slickPause");
2000            $(".slider-for").slick("slickSetOption", "autoplaySpeed", 10000);
2001            $(".slider-for").slick("slickPlay");
2002            // Reset progress bar transition duration to default before setting to 10s
2003            $(".progress-bar").css("transition-duration", "");
2004            $(".progress-bar").css("transition-duration", "10s");
2005        }
2006
2007        topStories.on("afterChange", function (event, slick, currentSlide) {
2008            $(".slick-slide").attr("data-current", false);
2009            $(".slick-current").attr("data-current", true);
2010            topStories
2011                .find('.slick-current[data-loaded= "true"]')
2012                .attr("data-loaded", false);
2013        });
2014
2015        function updateNavSlides(currentSlide) {
2016            const navSlider = topStories.find(".slider-nav");
2017            const allSlides = navSlider.find(".slick-slide:not(.slick-cloned)");
2018            const totalSlides = allSlides.length;
2019
2020            // Hide all slides first
2021            allSlides.hide();
2022
2023            // Show current slide
2024            allSlides.filter(`[data-slick-index="${currentSlide + 1}"]`).show();
2025
2026            // Show previous 3 slides
2027            for (let i = 1; i <= 3; i++) {
2028                const prevIndex = (currentSlide - i + totalSlides) % totalSlides;
2029                allSlides.filter(`[data-slick-index="${prevIndex + 1}"]`).show();
2030            }
2031
2032            // Show next 3 slides
2033            for (let i = 1; i <= 3; i++) {
2034                const nextIndex = (currentSlide + i) % totalSlides;
2035                allSlides.filter(`[data-slick-index="${nextIndex + 1}"]`).show();
2036            }
2037
2038            // Refresh slick to recalculate
2039            navSlider.slick("setPosition");
2040        }
2041
2042        // Update on slide change
2043        topStories
2044            .find(".slider-for")
2045            .on("afterChange", function (event, slick, currentSlide) {
2046                updateNavSlides(currentSlide);
2047                // Reset autoplay speed and progress bar duration
2048                $(".slider-for").slick("slickPause");
2049                $(".slider-for").slick("slickSetOption", "autoplaySpeed", 10000);
2050                $(".slider-for").slick("slickPlay");
2051                // Reset progress bar transition duration to default before setting to 10s
2052                $(".progress-bar").css("transition-duration", "");
2053                $(".progress-bar").css("transition-duration", "10s");
2054            });
2055    }
2056
2057    /* ------------------------ End Top Stories Component ------------------------ */
2058
2059    var helpCenterTopic = $(".faq-cmp");
2060    if (helpCenterTopic.length > 0) {
2061        var hash = window.location.hash;
2062        if (hash) {
2063            // $('html, body').animate({
2064            //   scrollTop: $($('[data-bs-target="'+hash+'"]')).offset().top - 64
2065            // }, 300, function(){
2066            //   $('[data-bs-target="'+hash+'"]').click();
2067            // });
2068            $('[data-bs-target="' + hash + '"]').click();
2069        }
2070    }
2071
2072    if ($(".event-form-cancel-button").length > 0) {
2073        $(".event-form-cancel-button").on("click", function (e) {
2074            var flag = false;
2075            var eventForm = $(this).closest("form");
2076            eventForm.find("input:not([type=hidden])").each(function () {
2077                if ($(this).val().length > 0) {
2078                    flag = true;
2079                }
2080            });
2081            eventForm.find("select").each(function () {
2082                if ($(this).val()) {
2083                    flag = true;
2084                }
2085            });
2086            if (flag) {
2087                e.preventDefault();
2088                $("#confirmationModal").modal("show");
2089                $(".discard-btn").on("click", function (e) {
2090                    if (history.length > 1) {
2091                        e.preventDefault();
2092                        history.back(1);
2093                    }
2094                });
2095            } else {
2096                // performance.navigation.type = 1 : refresh page
2097                // performance.navigation.type = 0 : from any page
2098                if (history.length > 1 && performance.navigation.type !== 1) {
2099                    e.preventDefault();
2100                    history.back(1);
2101                }
2102            }
2103        });
2104    }
2105    $("#send-sms").on("click", function (e) {
2106        e.preventDefault();
2107
2108        var phoneNumbers = [];
2109        var modal = $("#referFriendModal");
2110        $("#referFriendModal .phone-number input").each(function (e) {
2111            if ($(this).val()) {
2112                phoneNumbers.push($(this).val());
2113            }
2114        });
2115        if (phoneNumbers.length === 0) {
2116            modal.find(".invalid-feedback").show();
2117        } else {
2118            modal.find(".invalid-feedback").hide();
2119            var payloadData = {
2120                smsId: $("#send-sms").data("sms-id"),
2121                phoneNumbers: phoneNumbers,
2122            };
2123            $.ajax({
2124                url: "/api/notify/getphonenumbers",
2125                dataType: "json",
2126                type: "post",
2127                contentType: "application/json",
2128                data: JSON.stringify(payloadData),
2129                beforeSend: function () {
2130                    modal.find("input").val("");
2131                    modal.modal("hide");
2132                    // show loading status
2133                    $("#statusModal").modal("show");
2134                },
2135                success: function (data, textStatus, jQxhr) {
2136                    var res = data;
2137                    if (res) {
2138                        modal = $("#statusModal");
2139                        modal.removeClass("loading-modal").addClass("statusModal");
2140                        var modalContent = modal.find(".modal-content");
2141                        modalContent.html("");
2142                        var count = res.Total;
2143                        if (res.Status == "200") {
2144                            modalContent.append(
2145                                '<div class="modal-header"><span type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">Close</span></div><div class="modal-body"><i class="ri-checkbox-circle-fill"></i><h3 class="card-title">Success!</h3><div class="desc">Your referral code has been sent successfully.</div></div>'
2146                            );
2147                        } else {
2148                            if (res.FailedNumbers.length == count) {
2149                                // all sms are failed sending
2150                                modalContent.append(
2151                                    '<div class="modal-header"><span type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">Close</span></div><div class="modal-body"><i class="ri-close-circle-fill"></i><h3 class="card-title">Messages failed to sent!</h3><div class="desc">Sorry, your messages have not been sent. Please refresh your page and try again.</div></div>'
2152                                );
2153                            } else {
2154                                // some sms failed sending , the other is sent successfully
2155                                var failedCount = res.FailedNumbers.length;
2156                                var failedNumbers = "+65 " + res.FailedNumbers[0];
2157                                if (res.FailedNumbers.length == 2) {
2158                                    failedNumbers =
2159                                        failedNumbers + " and +65 " + res.FailedNumbers[1];
2160                                }
2161                                var textFailed =
2162                                    res.FailedNumbers.length == 1 ? " has " : " have ";
2163                                modalContent.append(
2164                                    '<div class="modal-header"><span type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">Close</span></div><div class="modal-body"><i class="ri-close-circle-fill"></i><h3 class="card-title">' +
2165                                    failedCount +
2166                                    " out of " +
2167                                    count +
2168                                    ' message failed to sent!</h3><div class="desc">Sorry, your message to ' +
2169                                    failedNumbers +
2170                                    textFailed +
2171                                    "not been sent. Please refresh your page and try again.</div></div>"
2172                                );
2173                            }
2174                        }
2175                    }
2176                },
2177                error: function (jqXhr, textStatus, errorThrown) {
2178                    console.log(errorThrown);
2179                },
2180            });
2181        }
2182    });
2183})(jQuery, window);
2184
2185// All Programme page and Pagination JS END
2186
2187function CopyToClipboard(id) {
2188    var r = document.createRange();
2189    r.selectNode(document.getElementById(id));
2190    window.getSelection().removeAllRanges();
2191    window.getSelection().addRange(r);
2192    document.execCommand("copy");
2193    window.getSelection().removeAllRanges();
2194}
2195
2196// Singal News page carousel
2197$(function () {
2198    var $slider = $("#singleNewsCarousel");
2199    if (!$slider) return;
2200    $slider.carousel();
2201});
2202
2203// For UFSE build your profile
2204// Change all to uppercase
2205$(document).ready(function () {
2206    $(".NRIC-Field").on("input", function () {
2207        $(this).val($(this).val().toUpperCase());
2208    });
2209});
2210
2211// For UFSE build your profile submit button
2212// Show loading gif and text if there's no error
2213// Hide the sign up rounded tag at the top of the page as well
2214$(".frmbtn").click(function () {
2215    setTimeout(function () {
2216        if ($(".input-validation-error").length === 0) {
2217            $(".txtLoader").removeClass("d-none");
2218            $(".txtLoadertxt").removeClass("d-none");
2219            $(".sign-up-tag").addClass("d-none");
2220        }
2221    }, 1);
2222});
2223
2224// Function to toggle visibility based on the selected category value
2225function toggleCategoryVisibility(categoryValue, selectElement) {
2226
2227   var selectedOption= selectElement.find('option[selected="selected"]');
2228    selectElement.find("option").each(function (index, element) {
2229
2230        if (!selectedOption &&  !element.hasAttribute("data-custom-attribute")) {
2231            selectElement.val(element);
2232        }
2233
2234        var isVisible =
2235            element.getAttribute("data-custom-attribute") === categoryValue;
2236        $(element).toggleClass("d-none", !isVisible);
2237        if (isVisible) {
2238            $(element).attr("hidden");
2239        } else {
2240            $(element).removeAttr("hidden");
2241        }
2242    });
2243}
2244
2245// Function to handle radio button change and toggle visibility
2246function handleRadioButtonChange(radioGroupName, selectElementId) {
2247    $("input[type=radio][data-sc-field-name=" + radioGroupName + "]").change(
2248        function () {
2249            var selectedValue = this.value;
2250            var selectElement = $(
2251                "select[data-sc-field-name=" + selectElementId + "]"
2252            );
2253            toggleCategoryVisibility(selectedValue, selectElement);
2254        }
2255    );
2256}
2257
2258// Function to initialize visibility based on default values
2259function initializeVisibility(radioGroupName, selectElementId) {
2260    var selectedValue = $(
2261        "input[type=radio][data-sc-field-name=" + radioGroupName + "]:checked"
2262    ).val();
2263    var selectElement = $("select[data-sc-field-name=" + selectElementId + "]");
2264    toggleCategoryVisibility(selectedValue, selectElement);
2265}
2266
2267// Coveo autofocus function
2268function handleAutoFocus() {
2269    const dropdownToggle1 = document.getElementById("search-group-mobile"); // mobile
2270    const dropdownToggle2 = document.getElementById("search-group-desktop"); // desktop
2271
2272    dropdownToggle1?.addEventListener("click", function () {
2273        setTimeout(() => {
2274            const shadowRoot =
2275                document.querySelector("#nav-search-mobile").shadowRoot;
2276            let inputElem = shadowRoot.querySelector("input"); // Access the input element within the shadow DOM
2277            inputElem.focus();
2278        }, 0);
2279    });
2280
2281    dropdownToggle2?.addEventListener("click", function () {
2282        setTimeout(() => {
2283            const shadowRoot = document.querySelector(
2284                "#nav-search-desktop"
2285            ).shadowRoot;
2286            let inputElem = shadowRoot.querySelector("input"); // Access the input element within the shadow DOM
2287            inputElem.focus();
2288        }, 0);
2289    });
2290}
2291
2292// Handle radio button changes and initialize visibility on document ready
2293$(document).ready(function () {
2294    handleRadioButtonChange("ExpertiseCategory", "Expertise");
2295    handleRadioButtonChange("CategoryBelong", "AddtionalExpertise");
2296    initializeVisibility("ExpertiseCategory", "Expertise");
2297    initializeVisibility("CategoryBelong", "AddtionalExpertise");
2298    handleAutoFocus();
2299});
2300
2301//Career Page
2302
2303(function () {
2304    // Scroll Reveal — auto-runs
2305    document.addEventListener("DOMContentLoaded", function () {
2306        try {
2307            const revealElements = document.querySelectorAll(".reveal-on-scroll");
2308
2309            const observer = new IntersectionObserver(
2310                (entries) => {
2311                    entries.forEach((entry) => {
2312                        if (entry.isIntersecting) {
2313                            entry.target.classList.add("is-visible");
2314                            observer.unobserve(entry.target); // ✅ Stop observing after reveal
2315                        }
2316                    });
2317                },
2318                { threshold: 0.1 }
2319            );
2320
2321            revealElements.forEach((el) => observer.observe(el));
2322        } catch (error) {
2323            console.error("Scroll reveal failed:", error);
2324        }
2325    });
2326
2327    // Career Swiper — only runs when explicitly called
2328    function initCareerSwiper() {
2329        try {
2330            const swiper = new Swiper(".carousel-swiper", {
2331                loop: true,
2332                autoHeight: true,
2333                slidesPerView: 1,
2334                spaceBetween: 30,
2335                navigation: {
2336                    nextEl: ".swiper-button-next",
2337                    prevEl: ".swiper-button-prev",
2338                },
2339            });
2340            return swiper;
2341        } catch (error) {
2342            console.error("Failed to initialize Career Swiper:", error);
2343            return null;
2344        }
2345    }
2346
2347    // Expose only this function to HTML
2348    window.initCareerSwiper = initCareerSwiper;
2349})();
2350
2351document.addEventListener("DOMContentLoaded", function () {
2352    const container = document.getElementById("form-main");
2353    const url = container?.getAttribute("profile-pic");
2354
2355    if (!url) return;
2356
2357    fetch(url)
2358        .then(r => r.blob())
2359        .then(b => {
2360            // Extract filename from URL
2361            let filename = url.split('/').pop().split('?')[0]; // handles query params too
2362            if (!filename.includes('.')) {
2363                // fallback to blob type if no extension
2364                const ext = b.type.split('/')[1];
2365                filename = `profile-picture.${ext}`;
2366            }
2367
2368            const f = new File([b], filename, { type: b.type });
2369            const dt = new DataTransfer();
2370            dt.items.add(f);
2371
2372            const input = document.getElementById("fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_d0ffac70-d85e-469f-867d-20c899265b87__Files");
2373            if (!input) return;
2374
2375            input.files = dt.files;
2376            input.dispatchEvent(new Event('change', { bubbles: true }));
2377
2378            console.log('Done:', f.name, f.type, f.size);
2379        })
2380        .catch(err => console.error("Image fetch failed:", err));
2381});
2382
2383document.addEventListener("DOMContentLoaded", function () {
2384    const input = document.getElementById("fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_d0ffac70-d85e-469f-867d-20c899265b87__Files");
2385    const container = document.querySelector(".upload-file-container");
2386
2387    // Handle file selection
2388    input.addEventListener("change", function () {
2389        const file = this.files[0];
2390        if (!file) return;
2391
2392        if (!file.type.startsWith("image/")) {
2393            alert("Please select an image");
2394            return;
2395        }
2396
2397        const reader = new FileReader();
2398
2399        reader.onload = function (e) {
2400            // Remove any previous preview image
2401            const existingPreview = container.nextElementSibling;
2402            if (existingPreview && existingPreview.classList.contains("dynamic-preview")) {
2403                existingPreview.remove();
2404            }
2405
2406            // Create new image dynamically
2407            const img = document.createElement("img");
2408            img.src = e.target.result;
2409            img.className = "dynamic-preview";
2410            img.style.display = "block";
2411            img.style.width = "100px";
2412            img.style.marginTop = "10px";
2413            img.style.paddingBottom = "10px";
2414
2415            // Insert image right after container
2416            //container.insertAdjacentElement("afterend", img);
2417        };
2418
2419        reader.readAsDataURL(file);
2420    });
2421
2422    // Event delegation for Remove button
2423    document.addEventListener("click", function (e) {
2424        if (e.target && e.target.classList.contains("remove-text")) {
2425            const existingPreview = container.nextElementSibling;
2426            if (existingPreview && existingPreview.classList.contains("dynamic-preview") && e.target.hasAttribute("type")) {
2427                //existingPreview.remove();
2428                input.value = ""; // reset file input
2429            }
2430        }
2431    });
2432});
2433
2434document.addEventListener("DOMContentLoaded", function () {
2435    const container = document.getElementById("form-main");
2436    if (!container) return;
2437
2438    // --- GLOBAL FETCH CACHE (avoid duplicate downloads) ---
2439    const fetchCache = {};
2440
2441    // --- 1. CONFIGURE ATTRIBUTE TO INPUT MAPPING ---
2442    const fileMappings = [
2443        {
2444            attribute: "portfoliofiles",
2445            inputId: "fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_a0745062-ad4b-44a3-b066-d80a81b89a94__Files",
2446            isConditional: true
2447        },
2448        {
2449            attribute: "awardsfiles",
2450            inputId: "fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_690c8ef5-fa7a-4ba3-b50d-ea812697b3a0__Files"
2451        },
2452        {
2453            attribute: "relevantmediafiles",
2454            inputId: "fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_xxx-relevantmedia" // replace with correct ID
2455        },
2456        {
2457            attribute: "accreditationsfiles",
2458            inputId: "fxb_6a5405b7-344f-4cca-9aa6-4f6e1b171067_Fields_15055262-cb27-4515-9422-602786e22d38__Files"
2459        }
2460    ];
2461
2462    // --- SINGLE OBSERVER (performance optimized) ---
2463    const globalFileUrlMap = {};
2464    const observer = new MutationObserver(() => {
2465        applyLinksToPreview(globalFileUrlMap);
2466    });
2467    observer.observe(container, { childList: true, subtree: true });
2468
2469    // --- 2. CONDITIONAL LOGIC FOR PORTFOLIOFILES ---
2470    const portfolioMapping = fileMappings.find(f => f.isConditional);
2471    if (portfolioMapping) {
2472        const portfolioInput = document.getElementById(portfolioMapping.inputId);
2473
2474        const accreditations = container.getAttribute("accreditationsfiles");
2475        const relevantMedia = container.getAttribute("relevantmediafiles");
2476        const awards = container.getAttribute("awardsfiles");
2477
2478        let mainFiles = "";
2479
2480        if ((!accreditations || accreditations.trim() === "") &&
2481            (!relevantMedia || relevantMedia.trim() === "") &&
2482            (!awards || awards.trim() === "")) {
2483            mainFiles = container.getAttribute("portfoliofiles") || "";
2484        } else {
2485            mainFiles = relevantMedia || "";
2486        }
2487
2488        if (portfolioInput && mainFiles) {
2489            processFiles(mainFiles, portfolioInput, globalFileUrlMap, fetchCache);
2490        }
2491    }
2492
2493    // --- 3. PROCESS OTHER ATTRIBUTES ---
2494    fileMappings.forEach(mapping => {
2495        if (mapping.isConditional) return;
2496
2497        const filesString = container.getAttribute(mapping.attribute);
2498        const input = document.getElementById(mapping.inputId);
2499
2500        if (!filesString || !input) return;
2501
2502        processFiles(filesString, input, globalFileUrlMap, fetchCache);
2503    });
2504});
2505
2506function processFiles(filesString, input, globalFileUrlMap, fetchCache) {
2507
2508    const files = filesString
2509        .split('|')
2510        .map(item => {
2511            const index = item.indexOf('~');
2512            if (index === -1) {
2513                console.warn("Invalid file entry:", item);
2514                return null;
2515            }
2516
2517            return [
2518                item.substring(0, index),
2519                item.substring(index + 1)
2520            ];
2521        })
2522        .filter(x => x && x[0] && x[1]);
2523
2524    const dt = new DataTransfer();
2525
2526    // --- FETCH FILES ---
2527    const fetchPromises = files.map(([url, filename]) => {
2528
2529        // --- FETCH CACHE ---
2530        if (!fetchCache[url]) {
2531            fetchCache[url] = fetch(url)
2532                .then(r => r.blob())
2533                .catch(err => {
2534                    console.warn("Failed to fetch:", url, err);
2535                    return null;
2536                });
2537        }
2538
2539        return fetchCache[url].then(blob => {
2540            if (!blob) return;
2541
2542            // --- fallback filename ---
2543            if (!filename || !filename.includes('.')) {
2544                filename = url.split('/').pop().split('?')[0];
2545            }
2546
2547            // --- PREVENT DUPLICATE FILENAMES ---
2548            let uniqueName = filename;
2549            let counter = 1;
2550
2551            while (globalFileUrlMap[uniqueName]) {
2552                uniqueName = `${filename} (${counter++})`;
2553            }
2554
2555            globalFileUrlMap[uniqueName] = url;
2556
2557            dt.items.add(new File([blob], uniqueName, { type: blob.type }));
2558        });
2559    });
2560
2561    Promise.all(fetchPromises).then(() => {
2562        if (dt.items.length > 0) {
2563            input.files = dt.files;
2564            input.dispatchEvent(new Event('change', { bubbles: true }));
2565
2566            setTimeout(() => applyLinksToPreview(globalFileUrlMap), 300);
2567        }
2568    });
2569
2570    // --- MANUAL FILE UPLOADS ---
2571    input.addEventListener('change', function () {
2572        Array.from(input.files).forEach(file => {
2573            if (!globalFileUrlMap[file.name]) {
2574                globalFileUrlMap[file.name] = URL.createObjectURL(file);
2575            }
2576        });
2577        applyLinksToPreview(globalFileUrlMap);
2578    });
2579}
2580// --- APPLY CLICKABLE LINKS ---
2581function applyLinksToPreview(mapping) {
2582    const fileTexts = document.querySelectorAll(".uploaded-file p");
2583
2584    fileTexts.forEach(p => {
2585        const fileName = p.textContent.trim();
2586        const url = mapping[fileName];
2587
2588        if (url && !p.getAttribute('data-linked')) {
2589            p.style.cursor = "pointer";
2590            p.style.textDecoration = "underline";
2591            p.style.color = "#007bff";
2592            p.setAttribute('data-linked', 'true');
2593
2594            p.onclick = function (e) {
2595                e.preventDefault();
2596                e.stopPropagation();
2597                window.open(url, '_blank');
2598            };
2599        }
2600    });
2601}
2602/* ==========================================
2603   PDF Annotation Link Layer (shared helper)
2604   ========================================== */
2605function buildAnnotationLayer(page, viewport, slot, insertBefore) {
2606    page.getAnnotations({ intent: 'display' }).then(function (annotations) {
2607        // Remove any previous annotation layer in this slot (re-render on zoom)
2608        var prev = slot.querySelector('.pb-annotation-layer');
2609        if (prev) prev.remove();
2610
2611        var linkAnnotations = [];
2612        for (var i = 0; i < annotations.length; i++) {
2613            if (annotations[i].subtype === 'Link' && annotations[i].url) {
2614                linkAnnotations.push(annotations[i]);
2615            }
2616        }
2617        if (linkAnnotations.length === 0) return;
2618
2619        var layer = document.createElement('div');
2620        layer.className = 'pb-annotation-layer';
2621        layer.style.width = Math.floor(viewport.width) + 'px';
2622        layer.style.height = Math.floor(viewport.height) + 'px';
2623
2624        for (var j = 0; j < linkAnnotations.length; j++) {
2625            var annot = linkAnnotations[j];
2626            var rect = annot.rect; // [x1, y1, x2, y2] in PDF coordinate space
2627
2628            // Transform PDF rect to viewport coordinates
2629            var topLeft = viewport.convertToViewportPoint(rect[0], rect[3]);
2630            var bottomRight = viewport.convertToViewportPoint(rect[2], rect[1]);
2631
2632            var left = Math.min(topLeft[0], bottomRight[0]);
2633            var top = Math.min(topLeft[1], bottomRight[1]);
2634            var width = Math.abs(bottomRight[0] - topLeft[0]);
2635            var height = Math.abs(bottomRight[1] - topLeft[1]);
2636
2637            var link = document.createElement('a');
2638            link.href = annot.url;
2639            link.target = '_blank';
2640            link.rel = 'noopener noreferrer';
2641            link.className = 'pb-annotation-link';
2642            link.style.left = left + 'px';
2643            link.style.top = top + 'px';
2644            link.style.width = width + 'px';
2645            link.style.height = height + 'px';
2646            link.title = annot.url;
2647
2648            layer.appendChild(link);
2649        }
2650
2651        if (insertBefore) {
2652            slot.insertBefore(layer, insertBefore);
2653        } else {
2654            slot.appendChild(layer);
2655        }
2656    });
2657}
2658
2659/* ==========================================
2660   AI Playbook PDF Viewer
2661   ========================================== */
2662(function pbInit() {
2663    if (typeof jQuery === 'undefined' || typeof pdfjsLib === 'undefined') { setTimeout(pbInit, 100); return; }
2664    var jQ = jQuery;
2665    var API_BASE = '/api/sitecore/PdfViewer';
2666    var currentPlaybookId = null;
2667    var currentPlaybookTitle = '';
2668
2669    // PDF.js setup
2670    pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
2671    var DPR = Math.min(window.devicePixelRatio || 1, 2);
2672    var ZOOM_STEPS = [0.5, 0.67, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3];
2673    var pdfState = { doc: null, scale: 1, currentPage: 1, rendering: false, renderQueued: false, observer: null, rawBuffer: null };
2674    var formObserver = null;
2675    var formSubmitted = false;
2676
2677    // Reference to the hidden Sitecore form source container
2678    var formSource = document.getElementById('pb-sitecore-form-source');
2679
2680    // Auto-open form if returning from a reload (form was in success state)
2681    var pendingPlaybook = sessionStorage.getItem('pb-pending-playbook');
2682    if (pendingPlaybook) {
2683        sessionStorage.removeItem('pb-pending-playbook');
2684        try {
2685            var pending = JSON.parse(pendingPlaybook);
2686            currentPlaybookId = pending.id;
2687            currentPlaybookTitle = pending.title;
2688            setTimeout(function () { showForm(); }, 500);
2689        } catch (e) { }
2690    }
2691
2692    // --- Card click ---
2693    jQ(document).on('click', '.ai-playbook-card', function (e) {
2694        e.preventDefault();
2695        var card = jQ(this);
2696        currentPlaybookId = card.data('playbook-id');
2697        currentPlaybookTitle = card.data('playbook-title') || card.find('.title').text().trim();
2698        if (!currentPlaybookId) return;
2699        jQ.ajax({
2700            url: API_BASE + '/CheckSession',
2701            method: 'GET',
2702            data: { playbookId: currentPlaybookId },
2703            dataType: 'json',
2704            success: function (resp) {
2705                if (resp.alreadySubmitted) { showPdf(currentPlaybookId, currentPlaybookTitle); }
2706                else { showForm(); }
2707            },
2708            error: function () { showForm(); }
2709        });
2710    });
2711
2712    // --- Close overlay ---
2713    jQ(document).on('click', '.playbook-modal__close, .playbook-overlay__backdrop', function () {
2714        jQ('#playbook-overlay').fadeOut(200, function () {
2715            resetViewer();
2716            returnFormToSource();
2717            jQ('.playbook-modal').removeClass('playbook-modal--viewer');
2718            jQ('#playbook-form-panel').show();
2719            jQ('#playbook-viewer-panel').hide();
2720        });
2721        jQ('body').css('overflow', '');
2722    });
2723    jQ(document).on('keydown', function (e) { if (e.which === 27 && jQ('#playbook-overlay').is(':visible')) { jQ('.playbook-modal__close').trigger('click'); } });
2724
2725    // --- Toolbar controls ---
2726    jQ(document).on('click', '#pb-prev', function () { goToPage(pdfState.currentPage - 1); });
2727    jQ(document).on('click', '#pb-next', function () { goToPage(pdfState.currentPage + 1); });
2728    jQ(document).on('change', '#pb-page-input', function () {
2729        var n = parseInt(jQ(this).val(), 10);
2730        if (n && n >= 1 && pdfState.doc && n <= pdfState.doc.numPages) { goToPage(n); }
2731        else { jQ(this).val(pdfState.currentPage); }
2732    });
2733    jQ(document).on('click', '#pb-zoom-out', function () { stepZoom(-1); });
2734    jQ(document).on('click', '#pb-zoom-in', function () { stepZoom(1); });
2735    jQ(document).on('click', '#pb-fit', function () { fitToWidth(); });
2736
2737    // Download — uses in-memory buffer so PDF URL is never exposed
2738    jQ(document).on('click', '#pb-download', function () {
2739        if (!pdfState.rawBuffer) return;
2740        var blob = new Blob([pdfState.rawBuffer], { type: 'application/pdf' });
2741        var url = URL.createObjectURL(blob);
2742        var a = document.createElement('a');
2743        a.href = url;
2744        a.download = (currentPlaybookTitle || 'playbook').replace(/[^a-zA-Z0-9 _-]/g, '') + '.pdf';
2745        document.body.appendChild(a);
2746        a.click();
2747        document.body.removeChild(a);
2748        setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
2749    });
2750
2751    // ==========================================
2752    // Sitecore Form — move, observe, reset
2753    // ==========================================
2754
2755    function showForm() {
2756        if (formSubmitted) {
2757            sessionStorage.setItem('pb-pending-playbook', JSON.stringify({ id: currentPlaybookId, title: currentPlaybookTitle }));
2758            window.location.reload();
2759            return;
2760        }
2761
2762        jQ('.playbook-modal').removeClass('playbook-modal--viewer');
2763        jQ('#playbook-form-panel').show();
2764        jQ('#playbook-viewer-panel').hide();
2765
2766        var formSlot = document.getElementById('pb-form-slot');
2767        if (formSource) {
2768            var formInner = formSource.querySelector('.pb-sitecore-form-inner');
2769            if (formInner) {
2770                formSlot.appendChild(formInner);
2771            }
2772        }
2773
2774        // Populate the hidden "ResourceName" field with the block name
2775        var resourceField = formSlot.querySelector('[data-sc-field-name="ResourceName"]');
2776        if (resourceField) {
2777            resourceField.value = currentPlaybookTitle;
2778        }
2779
2780        jQ('#playbook-overlay').fadeIn(200);
2781        jQ('body').css('overflow', 'hidden');
2782
2783        startFormObserver();
2784    }
2785
2786    function returnFormToSource() {
2787        if (formObserver) { formObserver.disconnect(); formObserver = null; }
2788        var formInner = document.querySelector('#pb-form-slot .pb-sitecore-form-inner');
2789        if (formInner && formSource) {
2790            formSource.appendChild(formInner);
2791        }
2792    }
2793
2794    function startFormObserver() {
2795        if (formObserver) formObserver.disconnect();
2796        var formSlot = document.getElementById('pb-form-slot');
2797        if (!formSlot) return;
2798
2799        // Track whether the user has clicked Submit so the observer
2800        // doesn't fire during initial load or unrelated DOM changes.
2801        var submitClicked = false;
2802
2803        var form = formSlot.querySelector('form[data-sc-fxb]');
2804        if (form) {
2805            jQ(form).on('click', 'input[type="submit"], button[type="submit"]', function () {
2806                submitClicked = true;
2807            });
2808        }
2809
2810        formObserver = new MutationObserver(function () {
2811            if (!submitClicked) return;
2812            var formSlotEl = document.getElementById('pb-form-slot');
2813            if (!formSlotEl) return;
2814
2815            // Case 1: Sitecore replaced the form entirely with a success message
2816            // (form element is gone, success h1 or text is present)
2817            var formEl = formSlotEl.querySelector('form[data-sc-fxb]');
2818            if (!formEl) {
2819                onFormSuccess();
2820                return;
2821            }
2822
2823            // Case 2: Form re-rendered after successful Submit (no validation errors)
2824            // Sitecore re-renders the form with empty validation spans on success.
2825            var errorSpans = formSlotEl.querySelectorAll('.field-validation-error');
2826            var hasErrors = false;
2827            for (var i = 0; i < errorSpans.length; i++) {
2828                if (errorSpans[i].textContent.trim()) {
2829                    hasErrors = true;
2830                    break;
2831                }
2832            }
2833            if (!hasErrors) {
2834                onFormSuccess();
2835            } else {
2836                // Validation failed — allow re-submission
2837                submitClicked = false;
2838            }
2839        });
2840
2841        formObserver.observe(formSlot, { childList: true, subtree: true });
2842    }
2843
2844    function onFormSuccess() {
2845		if (formSubmitted) return;
2846        if (formObserver) { formObserver.disconnect(); formObserver = null; }
2847        formSubmitted = true;
2848
2849        jQ.ajax({
2850            url: API_BASE + '/MarkSession',
2851            method: 'POST',
2852            data: { playbookId: currentPlaybookId },
2853            dataType: 'json'
2854        });
2855
2856        showPdf(currentPlaybookId, currentPlaybookTitle);
2857    }
2858
2859    // ==========================================
2860    // PDF Viewer
2861    // ==========================================
2862
2863    function showPdf(playbookId, title) {
2864        jQ('.playbook-modal').addClass('playbook-modal--viewer');
2865        jQ('#playbook-form-panel').hide();
2866        jQ('#playbook-viewer-panel').show();
2867        jQ('#playbook-viewer-title').text(title || 'AI Playbook');
2868        jQ('#pb-loading').show();
2869        jQ('#pb-viewer-scroll').hide();
2870        jQ('#pb-pages').empty();
2871        jQ('body').css('overflow', 'hidden');
2872
2873        jQ('#playbook-overlay').fadeIn(200, function () {
2874            var pdfUrl = API_BASE + '/GetPdf?playbookId=' + encodeURIComponent(playbookId);
2875            var xhr = new XMLHttpRequest();
2876            xhr.open('GET', pdfUrl, true);
2877            xhr.responseType = 'arraybuffer';
2878            xhr.onload = function () {
2879                if (xhr.status === 200) {
2880                    pdfState.rawBuffer = xhr.response.slice(0);
2881                    loadPdf(xhr.response);
2882                } else {
2883                    jQ('#pb-loading').hide();
2884                    jQ('#pb-viewer-scroll').show();
2885                    jQ('#pb-pages').html('<p style="text-align:center;color:#999;padding:40px;">Failed to load PDF. Please try again.</p>');
2886                }
2887            };
2888            xhr.onerror = function () {
2889                jQ('#pb-loading').hide();
2890                jQ('#pb-viewer-scroll').show();
2891                jQ('#pb-pages').html('<p style="text-align:center;color:#999;padding:40px;">Failed to load PDF. Please try again.</p>');
2892            };
2893            xhr.send();
2894        });
2895    }
2896
2897    function loadPdf(arrayBuffer) {
2898        pdfjsLib.getDocument({ data: arrayBuffer }).promise.then(function (doc) {
2899            pdfState.doc = doc;
2900            pdfState.currentPage = 1;
2901            jQ('#pb-page-count').text(doc.numPages);
2902            jQ('#pb-page-input').val(1);
2903            jQ('#pb-loading').hide();
2904            jQ('#pb-viewer-scroll').show();
2905            // Desktop: start at 125%; mobile: fit to width
2906            if (window.innerWidth > 640) { setScale(1.25); } else { fitToWidth(); }
2907        }).catch(function (err) {
2908            console.error('[PdfViewer] PDF.js error:', err);
2909            jQ('#pb-loading').hide();
2910            jQ('#pb-viewer-scroll').show();
2911            jQ('#pb-pages').html('<p style="text-align:center;color:#999;padding:40px;">Unable to render this PDF.</p>');
2912        });
2913    }
2914
2915    function renderAllPages() {
2916        if (!pdfState.doc) return;
2917        if (pdfState.rendering) { pdfState.renderQueued = true; return; }
2918        pdfState.rendering = true;
2919
2920        if (pdfState.observer) pdfState.observer.disconnect();
2921        if (pdfState.lazyObserver) pdfState.lazyObserver.disconnect();
2922        var pagesEl = document.getElementById('pb-pages');
2923        pagesEl.innerHTML = '';
2924
2925        var totalPages = pdfState.doc.numPages;
2926        pdfState.renderedPages = {};
2927
2928        var setupDone = 0;
2929        for (var i = 1; i <= totalPages; i++) {
2930            (function (pageNum) {
2931                pdfState.doc.getPage(pageNum).then(function (page) {
2932                    var viewport = page.getViewport({ scale: pdfState.scale });
2933                    var slot = document.createElement('div');
2934                    slot.className = 'pb-page-slot';
2935                    slot.setAttribute('data-page', pageNum);
2936                    slot.style.width = Math.floor(viewport.width) + 'px';
2937                    slot.style.height = Math.floor(viewport.height) + 'px';
2938                    slot.style.background = '#f5f5f5';
2939
2940                    var tag = document.createElement('span');
2941                    tag.className = 'pb-page-tag';
2942                    tag.textContent = pageNum;
2943                    slot.appendChild(tag);
2944
2945                    var existing = pagesEl.querySelectorAll('.pb-page-slot');
2946                    var inserted = false;
2947                    for (var k = 0; k < existing.length; k++) {
2948                        if (parseInt(existing[k].getAttribute('data-page'), 10) > pageNum) {
2949                            pagesEl.insertBefore(slot, existing[k]);
2950                            inserted = true;
2951                            break;
2952                        }
2953                    }
2954                    if (!inserted) pagesEl.appendChild(slot);
2955
2956                    setupDone++;
2957                    if (setupDone === totalPages) {
2958                        startLazyObserver();
2959                        observeCurrentPage();
2960                        pdfState.rendering = false;
2961                        if (pdfState.renderQueued) {
2962                            pdfState.renderQueued = false;
2963                            renderAllPages();
2964                        }
2965                        updateNavButtons();
2966                    }
2967                });
2968            })(i);
2969        }
2970    }
2971
2972    function startLazyObserver() {
2973        var scrollEl = document.getElementById('pb-viewer-scroll');
2974        pdfState.lazyObserver = new IntersectionObserver(function (entries) {
2975            for (var j = 0; j < entries.length; j++) {
2976                if (entries[j].isIntersecting) {
2977                    var slot = entries[j].target;
2978                    var pageNum = parseInt(slot.getAttribute('data-page'), 10);
2979                    if (!pdfState.renderedPages[pageNum]) {
2980                        pdfState.renderedPages[pageNum] = true;
2981                        renderPageInSlot(pageNum, slot);
2982                    }
2983                }
2984            }
2985        }, { root: scrollEl, rootMargin: '200px 0px' });
2986
2987        var slots = document.querySelectorAll('#pb-pages .pb-page-slot');
2988        for (var k = 0; k < slots.length; k++) {
2989            pdfState.lazyObserver.observe(slots[k]);
2990        }
2991    }
2992
2993    function renderPageInSlot(pageNum, slot) {
2994        pdfState.doc.getPage(pageNum).then(function (page) {
2995            var viewport = page.getViewport({ scale: pdfState.scale });
2996            var canvas = document.createElement('canvas');
2997            canvas.width = Math.floor(viewport.width * DPR);
2998            canvas.height = Math.floor(viewport.height * DPR);
2999            canvas.style.width = Math.floor(viewport.width) + 'px';
3000            canvas.style.height = Math.floor(viewport.height) + 'px';
3001
3002            var tag = slot.querySelector('.pb-page-tag');
3003            slot.insertBefore(canvas, tag);
3004            slot.style.background = '';
3005            slot.style.height = '';
3006
3007            var ctx = canvas.getContext('2d', { willReadFrequently: true });
3008            page.render({
3009                canvasContext: ctx,
3010                viewport: viewport,
3011                transform: DPR !== 1 ? [DPR, 0, 0, DPR, 0, 0] : null
3012            });
3013
3014            // Overlay clickable links from PDF annotations
3015            buildAnnotationLayer(page, viewport, slot, tag);
3016        });
3017    }
3018
3019    function observeCurrentPage() {
3020        var scrollEl = document.getElementById('pb-viewer-scroll');
3021        pdfState.observer = new IntersectionObserver(function (entries) {
3022            var best = null;
3023            for (var j = 0; j < entries.length; j++) {
3024                if (entries[j].isIntersecting && (!best || entries[j].intersectionRatio > best.intersectionRatio)) {
3025                    best = entries[j];
3026                }
3027            }
3028            if (best) {
3029                var pageNum = parseInt(best.target.getAttribute('data-page'), 10);
3030                pdfState.currentPage = pageNum;
3031                jQ('#pb-page-input').val(pageNum);
3032                updateNavButtons();
3033            }
3034        }, { root: scrollEl, threshold: [0.25, 0.5, 0.75] });
3035
3036        var slots = document.querySelectorAll('#pb-pages .pb-page-slot');
3037        for (var k = 0; k < slots.length; k++) {
3038            pdfState.observer.observe(slots[k]);
3039        }
3040    }
3041
3042    function goToPage(n) {
3043        if (!pdfState.doc) return;
3044        n = Math.max(1, Math.min(pdfState.doc.numPages, n));
3045        pdfState.currentPage = n;
3046        jQ('#pb-page-input').val(n);
3047        updateNavButtons();
3048        var slot = document.querySelector('#pb-pages .pb-page-slot[data-page="' + n + '"]');
3049        if (slot) slot.scrollIntoView({ behavior: 'smooth', block: 'start' });
3050    }
3051
3052    function updateNavButtons() {
3053        if (!pdfState.doc) return;
3054        jQ('#pb-prev').prop('disabled', pdfState.currentPage <= 1);
3055        jQ('#pb-next').prop('disabled', pdfState.currentPage >= pdfState.doc.numPages);
3056    }
3057
3058    function setScale(s) {
3059        pdfState.scale = Math.max(0.25, Math.min(4, s));
3060        jQ('#pb-zoom-label').text(Math.round(pdfState.scale * 100) + '%');
3061        renderAllPages();
3062    }
3063
3064    function stepZoom(dir) {
3065        var cur = pdfState.scale;
3066        var next;
3067        if (dir > 0) {
3068            next = null;
3069            for (var i = 0; i < ZOOM_STEPS.length; i++) { if (ZOOM_STEPS[i] > cur + 0.001) { next = ZOOM_STEPS[i]; break; } }
3070            if (!next) next = cur * 1.25;
3071        } else {
3072            next = null;
3073            for (var i = ZOOM_STEPS.length - 1; i >= 0; i--) { if (ZOOM_STEPS[i] < cur - 0.001) { next = ZOOM_STEPS[i]; break; } }
3074            if (!next) next = cur / 1.25;
3075        }
3076        setScale(next);
3077    }
3078
3079    function fitToWidth() {
3080        if (!pdfState.doc) return;
3081        pdfState.doc.getPage(pdfState.currentPage || 1).then(function (page) {
3082            var viewport = page.getViewport({ scale: 1 });
3083            var scrollEl = document.getElementById('pb-viewer-scroll');
3084            var available = scrollEl.clientWidth - 64;
3085            var newScale = Math.max(0.25, Math.min(4, available / viewport.width));
3086            pdfState.scale = newScale;
3087            jQ('#pb-zoom-label').text(Math.round(newScale * 100) + '%');
3088            renderAllPages();
3089        });
3090    }
3091
3092    function resetViewer() {
3093        if (pdfState.observer) pdfState.observer.disconnect();
3094        if (pdfState.lazyObserver) pdfState.lazyObserver.disconnect();
3095        pdfState.doc = null;
3096        pdfState.rawBuffer = null;
3097        pdfState.scale = 1;
3098        pdfState.currentPage = 1;
3099        pdfState.rendering = false;
3100        pdfState.renderQueued = false;
3101        pdfState.renderedPages = {};
3102        jQ('#pb-pages').empty();
3103        jQ('#pb-page-input').val(1);
3104        jQ('#pb-page-count').text('0');
3105        jQ('#pb-zoom-label').text('100%');
3106    }
3107})();
3108
3109/* ==========================================
3110   Teaser PDF Viewer — Membership-Gated
3111   ========================================== */
3112(function tpInit() {
3113    if (typeof jQuery === 'undefined' || typeof pdfjsLib === 'undefined') { setTimeout(tpInit, 100); return; }
3114    var jQ = jQuery;
3115    var API_BASE = '/api/sitecore/PdfViewer';
3116    var FREE_PAGES = 2;
3117
3118    pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
3119    var DPR = Math.min(window.devicePixelRatio || 1, 2);
3120    var ZOOM_STEPS = [0.5, 0.67, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3];
3121    var tpState = { doc: null, scale: 1, currentPage: 1, rendering: false, renderQueued: false, observer: null, lazyObserver: null, renderedPages: {}, accessLevel: 'anonymous', loginUrl: '' };
3122
3123    jQ(document).on('click', '.teaser-pdf-card', function (e) {
3124        e.preventDefault();
3125        var card = jQ(this);
3126        var pdfId = card.data('pdf-id');
3127        var pdfTitle = card.data('pdf-title') || card.find('.title').text().trim();
3128        tpState.accessLevel = card.data('access-level') || 'anonymous';
3129        tpState.loginUrl = card.data('login-url') || '/api/sitecore/LinkPassAPI/Login';
3130        if (!pdfId) return;
3131        showTeaserPdf(pdfId, pdfTitle);
3132    });
3133
3134    jQ(document).on('click', '#teaser-pdf-overlay .playbook-modal__close, #teaser-pdf-overlay .playbook-overlay__backdrop', function () {
3135        jQ('#teaser-pdf-overlay').fadeOut(200, function () { resetTeaserViewer(); });
3136        jQ('body').css('overflow', '');
3137    });
3138    jQ(document).on('keydown', function (e) { if (e.which === 27 && jQ('#teaser-pdf-overlay').is(':visible')) { jQ('#teaser-pdf-overlay .playbook-modal__close').first().trigger('click'); } });
3139
3140    jQ(document).on('click', '#tp-prev', function () { tpGoToPage(tpState.currentPage - 1); });
3141    jQ(document).on('click', '#tp-next', function () { tpGoToPage(tpState.currentPage + 1); });
3142    jQ(document).on('change', '#tp-page-input', function () {
3143        var n = parseInt(jQ(this).val(), 10);
3144        var maxPage = getMaxVisiblePage();
3145        if (n && n >= 1 && n <= maxPage) { tpGoToPage(n); }
3146        else { jQ(this).val(tpState.currentPage); }
3147    });
3148    jQ(document).on('click', '#tp-zoom-out', function () { tpStepZoom(-1); });
3149    jQ(document).on('click', '#tp-zoom-in', function () { tpStepZoom(1); });
3150    jQ(document).on('click', '#tp-fit', function () { tpFitToWidth(); });
3151
3152    function showTeaserPdf(pdfId, title) {
3153        resetTeaserViewer();
3154        jQ('#teaser-viewer-title').text(title || 'Document');
3155        jQ('#tp-loading').show();
3156        jQ('#tp-viewer-scroll').hide();
3157        jQ('body').css('overflow', 'hidden');
3158
3159        // Start XHR only after modal is fully visible — ensures clientWidth is accurate for fitToWidth
3160        jQ('#teaser-pdf-overlay').fadeIn(200, function () {
3161            var pdfUrl = API_BASE + '/GetPdf?playbookId=' + encodeURIComponent(pdfId);
3162            var xhr = new XMLHttpRequest();
3163            xhr.open('GET', pdfUrl, true);
3164            xhr.responseType = 'arraybuffer';
3165            xhr.onload = function () {
3166                if (xhr.status === 200) { loadTeaserPdf(xhr.response); }
3167                else {
3168                    jQ('#tp-loading').hide();
3169                    jQ('#tp-viewer-scroll').show();
3170                    jQ('#tp-pages').html('<p style="text-align:center;color:#999;padding:40px;">Failed to load PDF.</p>');
3171                }
3172            };
3173            xhr.onerror = function () {
3174                jQ('#tp-loading').hide();
3175                jQ('#tp-viewer-scroll').show();
3176                jQ('#tp-pages').html('<p style="text-align:center;color:#999;padding:40px;">Failed to load PDF.</p>');
3177            };
3178            xhr.send();
3179        });
3180    }
3181
3182    function loadTeaserPdf(arrayBuffer) {
3183        pdfjsLib.getDocument({ data: arrayBuffer }).promise.then(function (doc) {
3184            tpState.doc = doc;
3185            tpState.currentPage = 1;
3186            var displayCount = tpState.accessLevel === 'member' ? doc.numPages : Math.min(doc.numPages, FREE_PAGES + 1);
3187            jQ('#tp-page-count').text(displayCount);
3188            jQ('#tp-page-input').val(1);
3189            jQ('#tp-loading').hide();
3190            jQ('#tp-viewer-scroll').show();
3191            // Desktop: start at 125%; mobile: fit to width
3192            if (window.innerWidth > 640) { tpSetScale(1.25); } else { tpFitToWidth(); }
3193        }).catch(function (err) {
3194            console.error('[TeaserPdf] PDF.js error:', err);
3195            jQ('#tp-loading').hide();
3196            jQ('#tp-viewer-scroll').show();
3197            jQ('#tp-pages').html('<p style="text-align:center;color:#999;padding:40px;">Unable to render this PDF.</p>');
3198        });
3199    }
3200
3201    function tpRenderAllPages() {
3202        if (!tpState.doc) return;
3203        if (tpState.rendering) { tpState.renderQueued = true; return; }
3204        tpState.rendering = true;
3205
3206        if (tpState.observer) tpState.observer.disconnect();
3207        if (tpState.lazyObserver) tpState.lazyObserver.disconnect();
3208        var pagesEl = document.getElementById('tp-pages');
3209        pagesEl.innerHTML = '';
3210        tpState.renderedPages = {};
3211
3212        var totalPages = tpState.doc.numPages;
3213        var isMember = tpState.accessLevel === 'member';
3214        var pagesToCreate = isMember ? totalPages : Math.min(totalPages, FREE_PAGES + 1);
3215        var setupDone = 0;
3216
3217        for (var i = 1; i <= pagesToCreate; i++) {
3218            (function (pageNum) {
3219                tpState.doc.getPage(pageNum).then(function (page) {
3220                    var viewport = page.getViewport({ scale: tpState.scale });
3221                    var slot = document.createElement('div');
3222                    slot.className = 'pb-page-slot';
3223                    slot.setAttribute('data-page', pageNum);
3224                    slot.style.width = Math.floor(viewport.width) + 'px';
3225                    slot.style.height = Math.floor(viewport.height) + 'px';
3226                    slot.style.background = '#f5f5f5';
3227
3228                    if (!isMember && pageNum > FREE_PAGES) {
3229                        slot.classList.add('tp-blurred');
3230                        var blurOverlay = document.createElement('div');
3231                        blurOverlay.className = 'tp-blur-overlay';
3232                        slot.appendChild(blurOverlay);
3233                    }
3234
3235                    var tag = document.createElement('span');
3236                    tag.className = 'pb-page-tag';
3237                    tag.textContent = pageNum;
3238                    slot.appendChild(tag);
3239
3240                    var existing = pagesEl.querySelectorAll('.pb-page-slot');
3241                    var inserted = false;
3242                    for (var k = 0; k < existing.length; k++) {
3243                        if (parseInt(existing[k].getAttribute('data-page'), 10) > pageNum) {
3244                            pagesEl.insertBefore(slot, existing[k]);
3245                            inserted = true;
3246                            break;
3247                        }
3248                    }
3249                    if (!inserted) pagesEl.appendChild(slot);
3250
3251                    setupDone++;
3252                    if (setupDone === pagesToCreate) {
3253                        // Inject gate card after page 3 slot for non-members
3254                        if (!isMember) {
3255                            var gateSlot = pagesEl.querySelector('.pb-page-slot[data-page="' + (FREE_PAGES + 1) + '"]');
3256                            if (gateSlot) {
3257                                var gateCard = document.createElement('div');
3258                                gateCard.id = 'tp-gate-card';
3259                                gateCard.className = 'tp-gate-card';
3260                                gateCard.innerHTML =
3261                                    '<div class="tp-gate-icon">&#128274;</div>' +
3262                                    '<h3 class="tp-gate-title">Available to NTUC members only</h3>' +
3263                                    '<p class="tp-gate-desc">If you are a registered member, log in to continue.</p>' +
3264                                    '<a id="tp-login-btn" href="' + tpState.loginUrl + '" class="tp-gate-btn">Log in or join as a member</a>';
3265                                gateSlot.parentNode.insertBefore(gateCard, gateSlot);
3266                            }
3267                        }
3268                        tpStartLazyObserver();
3269                        tpObserveCurrentPage();
3270                        tpState.rendering = false;
3271                        if (tpState.renderQueued) {
3272                            tpState.renderQueued = false;
3273                            tpRenderAllPages();
3274                        }
3275                        tpUpdateNavButtons();
3276                    }
3277                });
3278            })(i);
3279        }
3280    }
3281
3282    function tpStartLazyObserver() {
3283        var scrollEl = document.getElementById('tp-viewer-scroll');
3284        tpState.lazyObserver = new IntersectionObserver(function (entries) {
3285            for (var j = 0; j < entries.length; j++) {
3286                if (entries[j].isIntersecting) {
3287                    var slot = entries[j].target;
3288                    var pageNum = parseInt(slot.getAttribute('data-page'), 10);
3289                    if (!tpState.renderedPages[pageNum]) {
3290                        tpState.renderedPages[pageNum] = true;
3291                        tpRenderPageInSlot(pageNum, slot);
3292                    }
3293                }
3294            }
3295        }, { root: scrollEl, rootMargin: '200px 0px' });
3296
3297        var slots = document.querySelectorAll('#tp-pages .pb-page-slot');
3298        for (var k = 0; k < slots.length; k++) {
3299            tpState.lazyObserver.observe(slots[k]);
3300        }
3301    }
3302
3303    function tpRenderPageInSlot(pageNum, slot) {
3304        tpState.doc.getPage(pageNum).then(function (page) {
3305            var viewport = page.getViewport({ scale: tpState.scale });
3306            var canvas = document.createElement('canvas');
3307            canvas.width = Math.floor(viewport.width * DPR);
3308            canvas.height = Math.floor(viewport.height * DPR);
3309            canvas.style.width = Math.floor(viewport.width) + 'px';
3310            canvas.style.height = Math.floor(viewport.height) + 'px';
3311
3312            var blurOverlay = slot.querySelector('.tp-blur-overlay');
3313            if (blurOverlay) {
3314                slot.insertBefore(canvas, blurOverlay);
3315            } else {
3316                var tag = slot.querySelector('.pb-page-tag');
3317                slot.insertBefore(canvas, tag);
3318            }
3319            slot.style.background = '';
3320            slot.style.height = '';
3321
3322            var ctx = canvas.getContext('2d', { willReadFrequently: true });
3323            page.render({
3324                canvasContext: ctx,
3325                viewport: viewport,
3326                transform: DPR !== 1 ? [DPR, 0, 0, DPR, 0, 0] : null
3327            });
3328
3329            // Overlay clickable links from PDF annotations
3330            var insertBefore = blurOverlay || slot.querySelector('.pb-page-tag');
3331            buildAnnotationLayer(page, viewport, slot, insertBefore);
3332        });
3333    }
3334
3335    function tpObserveCurrentPage() {
3336        var scrollEl = document.getElementById('tp-viewer-scroll');
3337        tpState.observer = new IntersectionObserver(function (entries) {
3338            var best = null;
3339            for (var j = 0; j < entries.length; j++) {
3340                if (entries[j].isIntersecting && (!best || entries[j].intersectionRatio > best.intersectionRatio)) {
3341                    best = entries[j];
3342                }
3343            }
3344            if (best) {
3345                var pageNum = parseInt(best.target.getAttribute('data-page'), 10);
3346                tpState.currentPage = pageNum;
3347                jQ('#tp-page-input').val(pageNum);
3348                tpUpdateNavButtons();
3349            }
3350        }, { root: scrollEl, threshold: [0.25, 0.5, 0.75] });
3351
3352        var slots = document.querySelectorAll('#tp-pages .pb-page-slot');
3353        for (var k = 0; k < slots.length; k++) {
3354            tpState.observer.observe(slots[k]);
3355        }
3356    }
3357
3358    function getMaxVisiblePage() {
3359        if (!tpState.doc) return 1;
3360        if (tpState.accessLevel === 'member') return tpState.doc.numPages;
3361        return Math.min(tpState.doc.numPages, FREE_PAGES + 1);
3362    }
3363
3364    function tpGoToPage(n) {
3365        if (!tpState.doc) return;
3366        var max = getMaxVisiblePage();
3367        n = Math.max(1, Math.min(max, n));
3368        tpState.currentPage = n;
3369        jQ('#tp-page-input').val(n);
3370        tpUpdateNavButtons();
3371        var slot = document.querySelector('#tp-pages .pb-page-slot[data-page="' + n + '"]');
3372        if (slot) slot.scrollIntoView({ behavior: 'smooth', block: 'start' });
3373    }
3374
3375    function tpUpdateNavButtons() {
3376        if (!tpState.doc) return;
3377        var max = getMaxVisiblePage();
3378        jQ('#tp-prev').prop('disabled', tpState.currentPage <= 1);
3379        jQ('#tp-next').prop('disabled', tpState.currentPage >= max);
3380    }
3381
3382    function tpSetScale(s) {
3383        tpState.scale = Math.max(0.25, Math.min(4, s));
3384        jQ('#tp-zoom-label').text(Math.round(tpState.scale * 100) + '%');
3385        tpRenderAllPages();
3386    }
3387
3388    function tpStepZoom(dir) {
3389        var cur = tpState.scale;
3390        var next;
3391        if (dir > 0) {
3392            next = null;
3393            for (var i = 0; i < ZOOM_STEPS.length; i++) { if (ZOOM_STEPS[i] > cur + 0.001) { next = ZOOM_STEPS[i]; break; } }
3394            if (!next) next = cur * 1.25;
3395        } else {
3396            next = null;
3397            for (var i = ZOOM_STEPS.length - 1; i >= 0; i--) { if (ZOOM_STEPS[i] < cur - 0.001) { next = ZOOM_STEPS[i]; break; } }
3398            if (!next) next = cur / 1.25;
3399        }
3400        tpSetScale(next);
3401    }
3402
3403    function tpFitToWidth() {
3404        if (!tpState.doc) return;
3405        tpState.doc.getPage(tpState.currentPage || 1).then(function (page) {
3406            var viewport = page.getViewport({ scale: 1 });
3407            var scrollEl = document.getElementById('tp-viewer-scroll');
3408            var available = scrollEl.clientWidth - 48;
3409            var newScale = Math.max(0.25, Math.min(4, available / viewport.width));
3410            tpState.scale = newScale;
3411            jQ('#tp-zoom-label').text(Math.round(newScale * 100) + '%');
3412            tpRenderAllPages();
3413        });
3414    }
3415
3416    function resetTeaserViewer() {
3417        if (tpState.observer) tpState.observer.disconnect();
3418        if (tpState.lazyObserver) tpState.lazyObserver.disconnect();
3419        tpState.doc = null;
3420        tpState.scale = 1;
3421        tpState.currentPage = 1;
3422        tpState.rendering = false;
3423        tpState.renderQueued = false;
3424        tpState.renderedPages = {};
3425        jQ('#tp-pages').empty(); // also removes the injected gate card
3426        jQ('#tp-page-input').val(1);
3427        jQ('#tp-page-count').text('0');
3428        jQ('#tp-zoom-label').text('100%');
3429    }
3430})();

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.