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.