PageSourceSearch

https://samusichalloffame.com/scripts/blazor-utility.js?6.88

js samusichalloffame.com collected 2026-09-25 01:51:27 UTC 35,124 bytes, 1,022 lines download raw bytes

1console.log("%cThis is a browser feature intended for developers. Do not paste any code here given to you by someone else. It may compromise your account or have other negative side effects.", "font-weight: bold; font-size: 14px;");
2
3(() => {
4    const maximumRetryCount = 3;
5    const retryIntervalMilliseconds = 5000;
6
7    const startReconnectionProcess = () => {
8        const reconnectModal = document.getElementById("reconnect-modal");
9        reconnectModal.style.display = "block";
10
11        let isCanceled = false;
12
13        (async () => {
14            try {
15                const result = await Blazor.reconnect();
16
17                if (!result) {
18                    location.reload();
19                    return;
20                }
21
22                return;
23            } catch {}
24
25            for (let i = 0; i < maximumRetryCount; i++) {
26                await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));
27
28                if (isCanceled)
29                    return;
30
31                try {
32                    const result = await Blazor.reconnect();
33
34                    if (!result) {
35                        location.reload();
36                        return;
37                    }
38
39                    return;
40                } catch {}
41            }
42
43            location.reload();
44        })();
45
46        return {
47            cancel: () => {
48                isCanceled = true;
49                reconnectModal.style.display = "none";
50            },
51        };
52    };
53
54    let currentReconnectionProcess = null;
55
56    Blazor.start({
57        circuit: {
58            reconnectionHandler: {
59                onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
60                onConnectionUp: () => {
61                    currentReconnectionProcess?.cancel();
62                    currentReconnectionProcess = null;
63                }
64            }
65        }
66    });
67})();
68
69function PreventInvalidInput() {
70    var quantityInputs = document.querySelectorAll('input[type="number"]');
71
72    for (var i = 0; i < quantityInputs.length; i++) {
73        var input = quantityInputs[i];
74
75        input.onfocus = function (e) {
76            if (e.target.step == "" || e.target.step == 1)
77                e.target.previousValue = parseInt(e.target.value);
78            else {
79                const trailingDecimalPoint = e.target.value[e.target.value.length - 1] == '.';
80                e.target.previousValue = parseFloat(e.target.value);
81
82                if (trailingDecimalPoint)
83                    e.target.previousValue += '.';
84            }
85        }
86
87        input.oninput = function (e) {
88            if (!(e.target.step == "" || e.target.step == 1))
89                return;
90
91            var value = e.target.value.replace("/[^0-9]/g", '');
92
93            if (value.length == 0)
94                return;
95
96            value = parseInt(value);
97
98            if (value == NaN)
99                value = e.target.previousValue;
100
101            if (e.target.min != "" && value < e.target.min)
102                value = e.target.min;
103            else if (e.target.max != "" && value > e.target.max)
104                value = e.target.max;
105
106            e.target.value = value;
107            e.target.previousValue = value;
108        }
109
110        input.onchange = function (e) {
111            this.changed = true;
112            var value = e.target.value.replace("/[^0-9.]/g", '');
113
114            if (value.length == 0)
115                return;
116
117            const isInt = e.target.step == "" || e.target.step == 1;
118            var number;
119
120            if (isInt) {
121                value = parseInt(value);
122                number = value;
123
124                if (value == NaN)
125                    value = e.target.previousValue;
126            } else {
127                value = parseFloat(value);
128                number = value;
129
130                if (value == NaN)
131                    value = e.target.previousValue;
132                else {
133                    if (e.target.hasAttribute("price")) {
134                        const options = {
135                            maximumFractionDigits: 2,
136                            currency: CURRENCY_CODE,
137                            style: "currency"
138                        }
139
140                        value = value.toLocaleString(undefined, options).replace(/[^\d.-]/g, '');
141                    }
142                }
143            }
144
145            if (number != NaN) {
146                if (e.target.min != "" && number < e.target.min)
147                    value = e.target.min;
148                else if (e.target.max != "" && number > e.target.max)
149                    value = e.target.max;
150            }
151
152            e.target.value = value;
153            e.target.previousValue = value;
154        }
155
156        if (!input.changed)
157            input.dispatchEvent(new Event('change'));
158    }
159
160    var textInputs = document.querySelectorAll('input[type="text"]');
161
162    for (var i = 0; i < textInputs.length; i++) {
163        var input = textInputs[i];
164
165        if (input.inputMode == "numeric") {
166            input.oninput = function (e) {
167                this.changed = true;
168                e.target.value = e.target.value.replace(/\D/g, '');
169            }
170        }
171
172        if (input.hasAttribute("invoiceid")) {
173            input.oninput = function (e) {
174                this.changed = true;
175
176                const rawInvoiceID = e.target.value.replace(/\W/ig, "").toUpperCase();
177                var invoiceID = rawInvoiceID.slice(0, INVOICE_PREFIX_LENGTH + INVOICE_NO_LENGTH);
178
179                for (var i = Math.min(INVOICE_PREFIX_LENGTH, invoiceID.length) - 1; i >= 0; i--) {
180                    var char = invoiceID.charAt(i);
181
182                    if (char.toLowerCase() == char.toUpperCase()) {
183                        if (i == 0)
184                            invoiceID = invoiceID.slice(1);
185                        else
186                            invoiceID = invoiceID.slice(0, i) + invoiceID.slice(i + 1);
187                    }
188                }
189
190                if (invoiceID.length > INVOICE_PREFIX_LENGTH)
191                    invoiceID = invoiceID.slice(0, INVOICE_PREFIX_LENGTH) + "-" + invoiceID.slice(INVOICE_PREFIX_LENGTH, INVOICE_PREFIX_LENGTH + INVOICE_NO_LENGTH + 1);
192
193                for (var j = Math.min(INVOICE_PREFIX_LENGTH + INVOICE_NO_LENGTH, invoiceID.length - 1); j > INVOICE_PREFIX_LENGTH; j--) {
194                    var char = invoiceID.charAt(j);
195
196                    if (!(/^\d+$/.test(char)))
197                        invoiceID = invoiceID.slice(0, j) + invoiceID.slice(j + 1);
198                }
199
200                e.target.value = invoiceID;
201            }
202        }
203
204        if (input.hasAttribute("key")) {
205            input.oninput = function (e) {
206                this.changed = true;
207
208                const rawkey = e.target.value.replace(/\W/ig, "").toUpperCase();
209                var key = rawkey.slice(0, KEY_SEGMENTS * KEY_SEGMENT_LENGTH);
210
211                for (var i = key.length - 1; i >= 0; i--) {
212                    if (!KEY_CHARACTERS.includes(key.charAt(i))) {
213                        if (i == 0)
214                            key = key.slice(1);
215                        else
216                            key = key.slice(0, i) + key.slice(i + 1);
217                    }
218                }
219
220                for (var j = KEY_SEGMENTS - 1; j > 0; j--) {
221                    var segmentOffset = j * KEY_SEGMENT_LENGTH;
222
223                    if (rawkey.length > segmentOffset)
224                        key = key.slice(0, segmentOffset) + KEY_SEPARATOR + key.slice(segmentOffset, KEY_INPUT_LENGTH);
225                }
226
227                e.target.value = key;
228            }
229        }
230
231        if (!input.changed)
232            input.dispatchEvent(new Event('input'));
233    }
234
235    var dateInputs = document.querySelectorAll('input[type="date"], input[type="datetime"], input[type="datetime-local"]');
236
237    for (var i = 0; i < dateInputs.length; i++) {
238        var input = dateInputs[i];
239
240        input.oninput = function (e) {
241            this.changed = true;
242            var value = e.target.value;
243
244            if (e.target.min != "" && value < e.target.min)
245                value = e.target.min;
246            else if (e.target.max != "" && value > e.target.max)
247                value = e.target.max;
248
249            e.target.value = value;
250            e.target.previousValue = value;
251        }
252
253        if (!input.changed)
254            input.dispatchEvent(new Event('input'));
255    }
256}
257
258function InitBlazorButton(buttonID) {
259    var button = document.getElementById(buttonID);
260
261    if (button == null)
262        return;
263
264    button.onclick = function () {
265        if (this.overlay == null) {
266            this.classList.add("button-display-loading");
267
268            var overlay = document.createElement("div");
269            overlay.classList.add("loading-button-overlay");
270            overlay.innerHTML = '<div class="loading-animation" style="--size:' + (this.offsetHeight * 0.75) + 'px"><span></span><span></span></div>';
271
272            const style = getComputedStyle(this);
273
274            if (style.backgroundClip == "text" || style.webkitBackgroundClip == "text") {
275                this.originalBackground = this.style.background;
276                this.style.background = "none";
277            }
278
279            this.appendChild(overlay);
280            this.overlay = overlay;
281        }
282    }
283}
284
285function HideButtonSaved(button) {
286    button.disabled = false;
287    button.classList.remove("button-display-loading");
288    button.classList.remove("button-display-saved");
289    button.style.background = button.originalBackground;
290    button.removeChild(button.overlay);
291    button.overlay = null;
292}
293
294function HideBlazorButtonLoadingOverlay(buttonID, savedMessage) {
295    var button = document.getElementById(buttonID);
296
297    if (button != null && button.overlay != null) {
298        if (button.hasAttribute("saver")) {
299            button.disabled = true;
300            button.classList.add("button-display-saved");
301            button.overlay.classList.remove("loading-button-overlay");
302            button.overlay.classList.add("button-saved-overlay");
303            button.overlay.innerHTML = '<img class="button-saved-icon" src="images/icons/tick.svg">' + savedMessage;
304            setTimeout(HideButtonSaved, 3000, button);
305        } else {
306            button.classList.remove("button-display-loading");
307            button.style.background = button.originalBackground;
308            button.removeChild(button.overlay);
309            button.overlay = null;
310        }
311    }
312}
313
314function InitBlazorForm(formID) {
315    var form = document.getElementById(formID);
316
317    if (form == null)
318        return;
319
320    form.onsubmit = function () {
321        if (this.overlay == null) {
322            this.classList.add("form-display-loading");
323
324            const smallestDimension = Math.min(this.offsetWidth, this.offsetHeight);
325
326            var overlay = document.createElement("div");
327            overlay.classList.add("loading-form-overlay");
328            overlay.innerHTML = '<div class="loading-animation" style="--size:' + (smallestDimension * 0.5) + 'px"><span></span><span></span></div>';
329
330            const style = getComputedStyle(form);
331
332            overlay.style.borderRadius = style.borderRadius;
333            overlay.style.width = "calc(100% + calc(" + style.borderWidth + " * 2))";
334            overlay.style.height = overlay.style.width;
335            overlay.style.left = "-" + style.borderWidth;
336            overlay.style.top = overlay.style.left;
337
338            this.appendChild(overlay);
339            this.overlay = overlay;
340        }
341    }
342}
343
344function HideBlazorFormLoadingOverlay(formID) {
345    var form = document.getElementById(formID);
346
347    if (form != null && form.overlay != null) {
348        form.classList.remove("form-display-loading");
349        form.removeChild(form.overlay);
350        form.overlay = null;
351    }
352}
353
354function ShowLoadingOverlays(classNames) {
355    var overlays = document.getElementsByClassName(classNames);
356
357    for (var i = 0; i < overlays.length; i++)
358        overlays[i].style.display = "flex";
359}
360
361function HideLoadingOverlays(classNames) {
362    var overlays = document.getElementsByClassName(classNames);
363
364    for (var i = 0; i < overlays.length; i++)
365        overlays[i].style.display = null;
366}
367
368function EnableScrolling() {
369    document.body.style.overflow = null;
370}
371
372function DisableScrolling() {
373    document.body.style.overflow = "hidden";
374}
375
376function AnimateOnScroll() {
377    const observer = new IntersectionObserver((entries) => {
378        entries.forEach((entry) => {
379            if (entry.isIntersecting) {
380                entry.target.classList.add('animate-on-scroll-sh
380ow');
381            }
382        });
383    });
384
385    const animateElements = document.querySelectorAll('.animate-on-scroll');
386    animateElements.forEach((el) => observer.observe(el));
387}
388
389function InitPhotoGallery(galleryID) {
390    galleryID = '#' + galleryID
391
392    var lightbox = new PhotoSwipeLightbox({
393        gallery: galleryID,
394        children: 'a',
395        pswpModule: PhotoSwipe
396    });
397
398    lightbox.init();
399}
400
401function InitPhotoGalleries() {
402    const galleries = document.getElementsByClassName("dynamic-photo-gallery");
403
404    for (var i = 0; i < galleries.length; i++) {
405        InitPhotoGallery(galleries[i].id);
406    }
407}
408
409function InitDropdownAdders() {
410    const dropdowns = document.querySelectorAll("select[adder]");
411
412    for (var i = 0; i < dropdowns.length; i++) {
413        const dropdown = dropdowns[i];
414
415        dropdown.onchange = function () {
416            dropdown.getElementsByTagName('option')[0].selected = true;
417        }
418    }
419}
420
421function InitTextareaCounter(textareaID, counterID) {
422    const textarea = document.getElementById(textareaID);
423    const counter = document.getElementById(counterID);
424
425    if (textarea == null || counter == null)
426        return;
427
428    counter.innerHTML = textarea.value.length + " / " + textarea.maxLength;
429
430    if (textarea.value.length > textarea.maxLength)
431        counter.classList.add("required");
432
433    textarea.oninput = function () {
434        counter.innerHTML = this.value.length + " / " + this.maxLength;
435
436        if (this.value.length > this.maxLength)
437            counter.classList.add("required");
438        else if (counter.classList.contains("required"))
439            counter.classList.remove("required");
440    }
441}
442
443function InitAccordions() {
444    const accordions = document.getElementsByClassName("accordion");
445
446    if (accordions == null)
447        return;
448
449    for (var i = 0; i < accordions.length; i++) {
450        const accordion = accordions[i];
451        const accordionItems = accordion.getElementsByClassName("accordion-item");
452
453        if (accordionItems == null)
454            continue;
455
456        for (var j = 0; j < accordionItems.length; j++) {
457            const accordionItem = accordionItems[j];
458            const accordionButton = accordionItem.getElementsByClassName("accordion-button")[0];
459            const accordionPanel = accordionItem.getElementsByClassName("accordion-panel")[0];
460            const accordionBody = accordionItem.getElementsByClassName("accordion-body")[0];
461            const accordionArrowButton = accordionItem.getElementsByClassName("accordion-arrow-button")[0];
462
463            if (accordionPanel.classList.contains("active"))
464                accordionBody.style.maxHeight = accordionBody.scrollHeight + "px";
465
466            accordionButton.onclick = function () {
467                const isActive = accordionPanel.classList.contains("active");
468                const accordionPanels = accordion.getElementsByClassName("accordion-panel");
469                const accordionBodies = accordion.getElementsByClassName("accordion-body");
470
471                for (var k = 0; k < accordionBodies.length; k++) {
472                    accordionPanels[k].classList.remove("active");
473                    accordionBodies[k].style.maxHeight = null;
474                }
475
476                if (!isActive) { 
477                    accordionPanel.classList.add("active");
478                    accordionBody.style.maxHeight = accordionBody.scrollHeight + "px";
479                }
480            };
481
482            accordionArrowButton.onclick = function() {
483                const isActive = accordionPanel.classList.contains("active");
484                const accordionPanels = accordion.getElementsByClassName("accordion-panel");
485                const accordionBodies = accordion.getElementsByClassName("accordion-body");
486
487                for (var k = 0; k < accordionBodies.length; k++) {
488                    accordionPanels[k].classList.remove("active");
489                    accordionBodies[k].style.maxHeight = null;
490                }
491
492                if (!isActive) {
493                    accordionPanel.classList.add("active");
494                    accordionBody.style.maxHeight = accordionBody.scrollHeight + "px";
495                }
496            };
497
498            try {
499                new ResizeObserver(() => {
500                    if (accordionPanel == null || accordionBody == null)
501                        return;
502
503                    if (accordionPanel.classList.contains("active")) {
504                        accordionBody.style.maxHeight = accordionBody.scrollHeight + "px";
505                    }
506                }).observe(accordionBody);
507            } catch {
508                addEventListener("resize", () => {
509                    if (accordionPanel == null || accordionBody == null)
510                        return;
511
512                    if (accordionPanel.classList.contains("active")) {
513                        accordionBody.style.maxHeight = accordionBody.scrollHeight + "px";
514                    }
515                });
516            }
517        }
518    }
519}
520
521function InitShowMoreButton(buttonID, containerID) {
522    const buttonContainer = document.getElementById(buttonID);
523    const button = buttonContainer.getElementsByTagName("button")[0];
524    const container = document.getElementById(containerID);
525
526    const computedStyle = getComputedStyle(container);
527
528    try {
529        new ResizeObserver(() => {
530            if (container.offsetHeight < parseInt(computedStyle.maxHeight)) {
531                buttonContainer.style.display = "none";
532            } else if (container.style.maxHeight != "unset") {
533                buttonContainer.style.display = "flex";
534
535                button.onclick = function () {
536                    container.style.maxHeight = "unset";
537                    buttonContainer.style.display = "none";
538                }
539            }
540        }).observe(container);
541    } catch {
542        buttonContainer.style.display = "none";
543        container.style.maxHeight = "unset";
544    }
545}
546
547function InitRadioButtons(radioName) {
548    const buttons = document.getElementsByName(radioName);
549
550    for (var i = 0; i < buttons.length; i++) {
551        const button = buttons[i];
552
553        button.onclick = function() {
554            for (var j = 0; j < buttons.length; j++) {
555                const radioButton = buttons[j];
556                radioButton.classList.remove("radio-selected");
557            }
558
559            this.classList.add("radio-selected");
560        }
561    }
562}
563
564function InitSortableLists() {
565    $('[sortable]').sortable({
566        handle: '[draggable-handle]',
567        stop: function (event, ui) {
568            const indices = this.querySelectorAll('[sortable-list-indices]')[0];
569            const items = this.querySelectorAll('[sortable-list-item]');
570
571            indices.value = "";
572
573            for (var i = 0; i < items.length; i++) {
574                const item = items[i];
575                const index = parseInt(item.id.replace("sortable-list-item-", ''));
576
577                indices.value += index.toString();
578
579                if (i != items.length - 1)
580                    indices.value += ',';
581            }
582
583            indices.dispatchEvent(new Event('change'));
584        }
585    });
586}
587
588function InitFileInputs() {
589    var lastDragTarget = null;
590
591    window.ondragenter = function (e) {
592        const inputs = $('input[type=file]:not(.input-file-no-drag)');
593
594        for (var i = 0; i < inputs.length; i++)
595            inputs[i].style.display = "block";
596
597        lastDragTarget = e.target;
598    }
599
600    window.ondragleave = function (e) {
601        if (e.target === lastDragTarget || e.target === document) {
602            const inputs = $('input[type=file]:not(.input-file-no-drag)');
603
604            for (var i = 0; i < inputs.length; i++)
605                inputs[i].style.display = null;
606        }
607    }
608
609    const inputs = $('input[type=file]:not(.input-file-no-drag)');
610
611    for (var i = 0; i < inputs.length; i++) {
612        const input = inputs[i];
613
614        input.ondragenter = function (e) {
615            this.style.outline = "3px dashed white";
616        }
617
618        input.ondragleave = function (e) {
619            this.style.outline = null;
620        }
621
622        input.ondrop = function (e) {
623            this.style.display = null;
624        }
625    }
626}
627
628function EnableFileInputs() {
629    const inputs = $('input[type=file]');
630
631    for (var i = 0; i < inputs.length; i++)
632        inputs[i].style.display = null;
633}
634
635function DisableFileInputs() {
636    const inputs = $('input[type=file]');
637
638    for (var i = 0; i < inputs.length; i++)
639        inputs[i].style.display = "none";
640}
641
642function InitHTMLEditor(editorID) {
643    const editor = document.getElementById(editorID);
644
645    editor.addEventListener("paste", function (e) {
646        if (e.target.classList.contains("rz-html-editor-content")) {
647            e.preventDefault();
648            var text = (e.originalEvent || e).clipboardData.getData("text/plain");
649            document.execCommand("insertHTML", false, text);
650        }
651    });
652
653    editor.oninput = function (e) {
654        if (e.target.classList.contains("rz-html-editor-content")) {
655            const divs = editor.querySelectorAll("div:not([class])");
656
657            for (var j = 0; j < divs.length; j++) {
658                var div = divs[j];
659                var p = document.createElement("p");
660
661                p.innerHTML = div.innerHTML;
662                div.parentNode.replaceChild(p, div);
663            }
664
665            const pasteSpans = editor.querySelectorAll("span[style*='background-color: initial; font-size: initial; font-weight: var(--bs-body-font-weight); text-align: var(--bs-body-text-align);']");
666
667            for (var j = 0; j < pasteSpans.length; j++) {
668                var pasteSpan = pasteSpans[j];
669                var parent = pasteSpan.parentNode;
670
671                while (pasteSpan.firstChild) {
672                    parent.insertBefore(pasteSpan.firstChild, pasteSpan);
673                }
674
675                parent.removeChild(pasteSpan);
676            }
677
678            const elements = editor.getElementsByTagName("*");
679
680            for (var j = 0; j < elements.length; j++) {
681                var element = elements[j];
682
683                element.style.backgroundColor = null;
684
685                if (element.style.fontSize == "initial")
686                    element.style.fontSize = null;
687
688                if (element.style.fontSize == "var(--bs-body-font-size)")
689                    element.style.fontSize = null;
690
691                if (element.style.fontWeight == "var(--bs-body-font-weight)")
692                    element.style.fontWeight = null;
693
694                if (element.style.textAlign == "var(--bs-body-text-align)")
695                    element.style.textAlign = null;
696
697                if (element.style.color == "rgb(255, 255, 255)")
698                    element.style.color = null;
699
700                if (element.style.backgroundImage == "var(--interact-gradient)" ||
701                    element.style.backgroundImage == "linear-gradient(135deg, rgb(185, 133, 253), rgb(255, 0, 217))")
702                    element.style.backgroundImage = null;
703            }
704
705            editor.querySelectorAll("[style='']").forEach((el) => {
706                el.removeAttribute("style");
707            });
708        }
709    };
710}
711
712function InitCarousel(carouselID, settings, itemWidth, speed) {
713    carouselID = "#" + carouselID;
714    settings = JSON.parse(settings);
715
716    (function ($) {
717        const carousel = $(carouselID);
718
719        carousel[0].slides = -1;
720        carousel.css("display", "block");
721        carousel.slick(settings);
722
723        const list = carousel.children(".slick-list")[0];
724
725        ResizeCarousel(carousel, list, itemWidth, speed);
726
727        addEventListener("resize", () => {
728            ResizeCarousel(carousel, list, itemWidth, speed);
729        });
730    })(jQuery);
731}
732
733function InitFullscreenCarousel(carouselID, settings) {
734    carouselID = "#" + carouselID;
735    settings = JSON.parse(settings);
736
737    (function ($) {
738        const carousel = $(carouselID);
739        carousel.css("display", "block");
740        carousel.slick(settings);
741    })(jQuery);
742}
743
744function ResizeCarousel(carousel, list, itemWidth, speed) {
745    const computedStyle = getComputedStyle(carousel[0]);
746    const slides = Math.max(parseInt((carousel[0].offsetWidth - (parseInt(computedStyle.marginLeft) + parseInt(computedStyle.marginRight))) / itemWidth), 1);
747
748    if (carousel.slides != slides) {
749        carousel.slides = slides;
750
751        carousel.slick('slickSetOption', {
752            autoplaySpeed: speed * slides,
753            slidesToShow: slides,
754            slidesToScroll: slides
755        }, true);
756
757        list.style.width = (slides * itemWidth) + "px";
758    }
759}
760
761function InitDescriptionButtons() {
762    var descriptions = document.getElementsByClassName("listing-long-description");
763
764    if (descriptions.length != 0) {
765        if (descriptions.length == 1) {
766            descriptions[0].style.display = "block";
767            return;
768        }
769
770        var descriptionButtons = document.getElementsByClassName("listing-description-button");
771
772        if (descriptions.length != descriptionButtons.length) {
773            console.error("descriptions.length doesn't match descriptionButtons.length");
774            return;
775        }
776
777        descriptions[0].style.display = "block";
778        descriptionButtons[0].disabled = true;
779
780        for (var i = 0; i < descriptionButtons.length; i++) {
781            const index = i;
782            const button = descriptionButtons[i];
783
784            button.onclick = function () {
785                for (var j = 0; j < descriptionButtons.length; j++) {
786                    descriptions[j].style.display = "none";
787                    descriptionButtons[j].disabled = false;
788                }
789
790                descriptions[index].classList.remove("listing-component-fade-in");
791                descriptions[index].style.display = "block";
792                descriptions[index].classList.add("listing-component-fade-in");
793                this.disabled = true;
794            }
795        }
796    }
797}
798
799function InitCodeScanner(id) {
800    var selectedDeviceId = "";
801    const codeReader = new ZXing.BrowserMultiFormatReader();
802    const SCAN_INTERVAL = 500;
803
804    var video = document.getElementById(id + "-video");
805    var canvas = document.getElementById(id + "-canvas");
806    var frame = document.getElementById(id + "-frame");
807    var zoomSlider = document.getElementById(id + "-zoom-slider");
808
809    var cameraScanSettings;
810
811    try {
812        cameraScanSettings = JSON.parse(document.cookie.match("(^|;)\\s*camera_scan_settings\\s*=\\s*([^;]+)")?.pop());
813        selectedDeviceId = cameraScanSettings.deviceId;
814        zoomSlider.value = cameraScanSettings.zoom;
815    } catch (e) {
816        cameraScanSettings = {
817            deviceId: "",
818            zoom: zoomSlider.value
819        };
820    }
821
822    navigator.mediaDevices.getUserMedia({ video: true }).then(() => {
823        codeReader.listVideoInputDevices().then((videoInputDevices) => {
824            const sourceSelect = document.getElementById(id + "-source-select");
825            const controlsContainer = document.getElementById(id + "-controls");
826
827            if (selectedDeviceId == "")
828                selectedDeviceId = videoInputDevices[0].deviceId;
829
830            if (videoInputDevices.length >= 1) {
831                videoInputDevices.forEach((element) => {
832                    const sourceOption = document.createElement("option");
833                    sourceOption.text = element.label;
834                    sourceOption.value = element.deviceId;
835
836                    if (sourceOption.value == selectedDeviceId)
837                        sourceOption.selected = true;
838
839                    sourceSelect.appendChild(sourceOption);
840                });
841
842                sourceSelect.onchange = () => {
843                    selectedDeviceId = sourceSelect.value;
844                };
845
846                const sourceSelectPanel = document.getElementById(id + "-source-select-container");
847                sourceSelectPanel.style.display = "block";
848            }
849
850            controlsContainer.style.display = "flex";
851
852            document.getElementById(id + "-zoom-slider").addEventListener("input", () => {
853                frame.style.width = video.clientWidth * zoomSlider.value + "px";
854                frame.style.height = video.clientHeight * zoomSlider.value + "px";
855
856                cameraScanSettings.zoom = zoomSlider.value;
857                SaveScanCameraSettings(cameraScanSettings);
858            });
859
860            document.getElementById(id + "-start-button").addEventListener("click", () => {
861                cameraScanSettings.deviceId = selectedDeviceId;
862                SaveScanCameraSettings(cameraScanSettings);
863
864                navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" }, deviceId: selectedDeviceId }).then(stream => {
865                    videoStream = stream;
866
867                    video.srcObject = stream;
868                    video.play();
869
870                    video.addEventListener("play", () => {
871                        canvas.width = video.videoWidth;
872                        canvas.height = video.videoHeight;
873
874                        frame.style.width = video.clientWidth * zoomSlider.value + "px";
875                        frame.style.height = video.clientHeight * zoomSlider.value + "px";
876
877                        document.getElementById(id + "-zoom-container").style.display = "flex";
878                        frame.style.display = "block";
879
880                        ScanFrame();
881                    });
882                });
883
884                controlsContainer.remove();
885            });
886        })
887        .catch((err) => {
888            console.error(err)
889        });
890    })
891    .catch((e) => {
892        document.getElementById(id + "-error").style.display = "block";
893    });
894
895    function ScanFrame() {
896        if (document.querySelector("video")) {
897            canvas.getContext("2d").drawImage(
898                video,
899                (video.videoWidth - video.videoWidth * zoomSlider.value) / 2,
900                (video.videoHeight - video.videoHeight * zoomSlider.value) / 2,
901                video.videoWidth * zoomSlider.value,
902                video.videoHeight * zoomSlider.value,
903                0,
904                0,
905                canvas.width,
906                canvas.height
907            );
908
909            canvas.toBlob(blob => {
910                codeReader.decodeFromImage(null, URL.createObjectURL(blob))
911                    .then(Found)
912                    .catch((e) => { });
913
914                setTimeout(ScanFrame, SCAN_INTERVAL);
915            });
916        }
917    }
918
919    function Found(result) {
920        try { return DotNet.invokeMethodAsync("GrapeWebsite", "JSSubmitCode", result.text); }
921        catch (error) { console.error(error); }
922    }
923}
924
925function SaveScanCameraSettings(cameraScanSettings) {
926    var date = new Date();
927    date.setTime(date.getTime() + 1209600000); //14 days
928    document.cookie = "camera_scan_settings=" + JSON.stringify(cameraScanSettings) + ";expires=" + date + ";path=/;samesite=strict;secure";
929}
930
931function CloseCameraStreams() {
932    try {
933        const video = document.querySelector("video");
934        const mediaStream = video.srcObject;
935        const tracks = mediaStream.getTracks();
936        tracks.forEach(track => track.stop());
937    } catch {}
938}
939
940function InitRECAPTCHA() {
941    grecaptcha.ready(function () {
942        grecaptcha.render("recaptcha-container", {
943            sitekey: RECAPTCHA_SITE_KEY
944        });
945    });
946}
947
948async function RECAPTCHASuccess(responseToken) {
949    try { DotNet.invokeMethodAsync("GrapeWebsite", "JSRECAPTCHASuccess", responseToken); }
950    catch (error) { console.error(error); }
951}
952
953function RenderCheckoutPayPalButtons() {
954    if (!paypalLoaded)
955        return false;
956
957    window.paypal
958        .Buttons({
959            style: {
960                shape: "rect",
961                layout: "vertical",
962            },
963            createOrder: PayPalCheckoutCreateOrder,
964            onApprove: PayPalCheckoutOnApprove
965        })
966        .render("#paypal-button-container");
967
968    return true;
969}
970
971async function PayPalCheckoutCreateOrder() {
972    return await DotNet.invokeMethodAsync("GrapeWebsite", "JSCheckoutCreateOrder");
973}
974
975async function PayPalCheckoutOnApprove(data, actions) {
976    await DotNet.invokeMethodAsync("GrapeWebsite", "JSCheckoutApproveOrder");
977}
978
979function RenderBookingPayPalButtons() {
980    if (!paypalLoaded)
981        return false;
982
983    window.paypal
984        .Buttons({
985            style: {
986                shape: "rect",
987                layout: "vertical",
988            },
989            createOrder: PayPalBookingCreateOrder,
990            onApprove: PayPalBookingOnApprove
991        })
992        .render("#paypal-button-container");
993
994    return true;
995}
996
997async function PayPalBookingCreateOrder() {
998    return await DotNet.invokeMethodAsync("GrapeWebsite", "JSBookingCreateOrder");
999}
1000
1001async function PayPalBookingOnApprove(data, actions) {
1002    await DotNet.invokeMethodAsync("GrapeWebsite", "JSBookingApproveOrder");
1003}
1004
1005function CalculateScrollbarWidth() {
1006    var scrollDiv = document.createElement("div");
1007    scrollDiv.className = "scrollbar-measure";
1008    document.body.appendChild(scrollDiv);
1009
1010    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
1011    document.body.style.setProperty("--scrollbar-width", scrollbarWidth + "px");
1012
1013    document.body.removeChild(scrollDiv);
1014}
1015
1016function ScrollToTop() {
1017    window.scrollTo({ top: 0, behavior: "smooth" });
1018}
1019
1020function ScrollIntoView(id) {
1021    document.getElementById(id).scrollIntoView();
1022}

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.