1$(document).on('click', '.open-trailer-alert', {}, function (e) { 2 3 e.preventDefault(); 4 var $alert = $("#traileralert"); 5 $alert.fadeIn(150); 6 $alert.find(".alert-edit-form").addClass("open"); 7 $("body").addClass("alert-open"); 8}); 9 10$(document).on('click', '.change-reg', {}, function (e) { 11 12 e.preventDefault(); 13 var $alert = $("#changeregalert"); 14 $alert.fadeIn(150); 15 $alert.find(".alert-edit-form").addClass("open"); 16 $("body").addClass("alert-open"); 17}); 18 19$(document).on('click', '.open-login-alert', {}, function (e) { 20 e.preventDefault(); 21 var $alert = $("#loginalert"); 22 $alert.fadeIn(150); 23 $alert.find(".alert-edit-form").addClass("open"); 24 $("body").addClass("alert-open"); 25 26}); 27 28$(document).on('click', '.add-vehicle-open', {}, function (e) { 29 30 e.preventDefault(); 31 var $alert = $("#addvehiclealert"); 32 $alert.fadeIn(150); 33 $alert.find(".alert-edit-form").addClass("open"); 34 $("body").addClass("alert-open"); 35}); 36 37$(document).on('click', '.pickstation', {}, function (e) { 38 39 e.preventDefault(); 40 var $alert = $("#mapoverlay"); 41 $alert.fadeIn(150); 42 $alert.find(".alert-edit-form").addClass("open"); 43 $("body").addClass("alert-open"); 44 initMap(); 45 $(document).on("keydown", function (keyEvent) { 46 if (keyEvent.key === "Escape") { 47 closeAlert(); 48 } 49 }); 50}); 51 52$(document).on('click', '.close-alert', {}, function (e) { 53 e.preventDefault(); 54 closeAlert(); 55}); 56 57function closeAlert() { 58 $(".alert-edit-form").removeClass("open"); 59 $("body").removeClass("alert-open"); 60 $(".alert").fadeOut(200); 61} 62 63$(document).ready(function () { 64 $("[data-type='bw-modal']").on("click", function (e) { 65 e.preventDefault(); 66 const $this = $(this); 67 const $modal = $("#generalmodal"); 68 $modal.find(".bw-modal-body-content").html($this.next().html()); 69 $modal.fadeIn(150); 70 $modal.find(".bw-modal-body").addClass("open"); 71 $modal.trigger("opened"); 72 $("body").addClass("bw-modal-open"); 73 74 $modal.find(".bw-modal-close").one("click", function () { 75 closeModal($modal); 76 }); 77 $modal.on("click", function (clickEvent) { 78 if ($(clickEvent.target).hasClass("bw-modal")) { 79 closeModal($modal); 80 } 81 }); 82 $(document).on("keydown", function (keyEvent) { 83 if (keyEvent.key === "Escape") { 84 closeModal($modal); 85 } 86 }); 87 }); 88 89 const closeModal = function (modal) { 90 modal.fadeOut(250); 91 modal.find(".bw-modal-body").removeClass("open"); 92 $("body").removeClass("bw-modal-open"); 93 }; 94}); 95 96/*Start of portal recurring timeslots*/ 97 98$(document).on('click', '.send-email-open', {}, function (e) { 99 e.preventDefault(); 100 const $this = $(this); 101 var $alert = $("#sendemailalert"); 102 $alert.fadeIn(150); 103 $alert.find(".alert-edit-form").addClass("open"); 104 $("body").addClass("alert-open"); 105 $("#currentStation").val($this.data('station')); 106 $("#currentDate").val($this.data('bookingdate')); 107}); 108 109//$(document).on('click', '#sendemailalert', {}, function (e) { 110// e.preventDefault(); 111// $(".alert-edit-form").removeClass("open"); 112// $("body").removeClass("alert-open"); 113// $("#currentStation").val(''); 114// $("#currentDate").val(''); 115// $("#alertmail").val(''); 116// $("#addregrerror").html(""); 117// $(".alert").fadeOut(200); 118//}); 119 120$(document).on('click', '.close-alert', {}, function (e) { 121 e.preventDefault(); 122 $(".alert-edit-form").removeClass("open"); 123 $("body").removeClass("alert-open"); 124 $("#currentStation").val(''); 125 $("#currentDate").val(''); 126 $("#alertmail").val(''); 127 $("#alerttext").val(''); 128 $("#addregrerror").html(""); 129 $(".alert").fadeOut(200); 130 $(".booking-mail-wrapper").removeClass("hidden"); 131 $(".portal-button-wrapper").removeClass("hidden"); 132}); 133 134$(".send-mail-button").on("click", function (e) { 135 var $this = $(this); 136 $("#addregrerror").html(""); 137 if (!$this.hasClass("disabled")) { 138 if (isValidEmailAddress($("#alertmail").val())) { 139 if ($("#alerttext").val().length < 251) { 140 $("#alertmail").attr("disabled", "disabled"); 141 $("#loading").addClass("show"); 142 $this.addClass("disabled"); 143 $.ajax({
144 contentType: "application/json; charset=utf-8", 145 dataType: "json", 146 url: "/PortalRecurringPage/SendEmail?email=" + $("#alertmail").val() + "&station=" + $("#currentStation").val() + "&time=" + $("#currentDate").val() + "&message=" + $("#alerttext").val(), 147 type: "GET", 148 cache: false, 149 success: function (data) { 150 if (data.success === true) { 151 $("#loading").removeClass("show"); 152 $("#addregrerror").append("<div class=\"success margin-top-xl\">Ditt email är nu skickat.</div>"); 153 $this.removeClass("disabled"); 154 $("#alertmail").removeAttr("disabled"); 155 $(".booking-mail-wrapper").addClass("hidden"); 156 $(".portal-button-wrapper").addClass("hidden"); 157 } else { 158 $("#loading").removeClass("show"); 159 $("#addregrerror").append("<div class=\"error margin-top\">Något gick fel. Kunde inte skicka ditt email.</div>"); 160 $this.removeClass("disabled"); 161 $("#alertmail").removeAttr("disabled"); 162 } 163 }, 164 error: function () { 165 } 166 }); 167 } else { 168 $("#addregrerror").append("<div class=\"error margin-bottom\"><strong>\"" + 169 $("#alerttext").val().length + 170 "\"</strong>/250 tecken.</div>"); 171 } 172 } else { 173 $("#addregrerror").append("<div class=\"error margin-bottom\"><strong>\"" + 174 $("#alertmail").val() + 175 "\"</strong> är ingen giltigt email</div>"); 176 177 $this.removeClass("disabled"); 178 $("#alertmail").removeAttr("disabled"); 179 } 180 } 181}); 182 183/*End of portal recurring timeslots*/ 184/* 185Initializes and manages a custom scrollbar: 186updates handle size, 187synchronizes handle movement with content scrolling, 188supports drag - and - click operations, 189and accommodates both mouse and touch inputs for a responsive user experience. 190*/ 191$(document).ready(function () { 192 fixBrokenStationScrollContainer(); 193 194 $('.scrollable-area').each(function () { 195 const scrollContent = $(this).find('.scroll-content'); 196 const customHandle = $(this).find('.custom-handle'); 197 const customScrollbar = $(this).find('.custom-scrollbar'); 198 199 if (!scrollContent || !customHandle || !customScrollbar) { 200 return; 201 } 202 203 function updateHandleWidth() { 204 if (!scrollContent || !customScrollbar) { 205 return; 206 } 207 208 const ratio = scrollContent.outerWidth() / scrollContent.get(0).scrollWidth; 209 const handleWidth = ratio * customScrollbar.outerWidth(); 210 customHandle.css('width', `${handleWidth}px`); 211 } 212 213 function syncScroll() { 214 if (!scrollContent || !customHandle || !customScrollbar) { 215 return; 216 } 217 218 const scrollRatio = scrollContent.get(0).scrollLeft / (scrollContent.get(0).scrollWidth - scrollContent.outerWidth()); 219 const handlePosition = scrollRatio * (customScrollbar.outerWidth() - customHandle.outerWidth()); 220 customHandle.css('left', `${handlePosition}px`); 221 } 222 223 function startDrag(e) { 224 if (!customHandle || !customScrollbar) { 225 return; 226 } 227 228 // Determine if it's a touch event or a mouse event and set the starting point accordingly 229 const startX = e.type === 'touchstart' ? e.touches[0].pageX : e.pageX; 230 231 const handleRect = customHandle.get(0).getBoundingClientRect(); 232 const scrollbarRect = customScrollbar.get(0).getBoundingClientRect();
233 const maxScrollLeft = scrollContent.get(0).scrollWidth - scrollContent.outerWidth(); 234 let startLeft = handleRect.left - scrollbarRect.left; 235 236 function onMove(e) { 237 // Determine if it's a touch event or a mouse event and set the current point accordingly 238 const currentX = e.type === 'touchmove' ? e.touches[0].pageX : e.pageX; 239 const dx = currentX - startX; 240 const newLeft = Math.min(Math.max(0, startLeft + dx), customScrollbar.outerWidth() - handleRect.width); 241 const scrollRatio = newLeft / (customScrollbar.outerWidth() - handleRect.width); 242 scrollContent.get(0).scrollLeft = scrollRatio * maxScrollLeft; 243 } 244 245 function onEnd() { 246 if (document) { 247 document.removeEventListener('mousemove', onMove); 248 document.removeEventListener('mouseup', onEnd); 249 document.removeEventListener('touchmove', onMove); 250 document.removeEventListener('touchend', onEnd); 251 } 252 } 253 254 if (document) { 255 document.addEventListener(e.type === 'touchstart' ? 'touchmove' : 'mousemove', onMove); 256 document.addEventListener(e.type === 'touchstart' ? 'touchend' : 'mouseup', onEnd); 257 } 258 } 259 260 function handleScrollbarClick(e) { 261 if (!customHandle || !customScrollbar) { 262 return; 263 } 264 265 console.log('handleScrollbarClick'); 266 console.log('e:', e); 267 console.log('customHandle:', customHandle); 268 console.log('customScrollbar:', customScrollbar); 269 270 // Avoid clicks on the handle 271 if (e.target === customHandle) { 272 console.log('Clicked on the handle'); 273 return; 274 } 275 276 const targetRect = customScrollbar.get(0).getBoundingClientRect(); 277 const handleRect = customHandle.get(0).getBoundingClientRect(); 278 const clickPosition = ((e.pageX || e.touches[0].pageX) - targetRect.left) - (handleRect.width / 2); // Center the handle on the click 279 const maxPosition = targetRect.width - handleRect.width; 280 const newPosition = Math.min(Math.max(0, clickPosition), maxPosition); 281 const scrollRatio = newPosition / maxPosition; 282 const maxScrollLeft = scrollContent.get(0).scrollWidth - scrollContent.outerWidth(); 283 scrollContent.scrollLeft = scrollRatio * maxScrollLeft; 284 } 285 286 updateHandleWidth(); 287 window.addEventListener('resize', updateHandleWidth); 288 scrollContent.on('scroll', syncScroll); 289 customHandle.on('mousedown', startDrag); 290 customHandle.on('touchstart', startDrag, { passive: true }); 291 customScrollbar.on('click', handleScrollbarClick); 292 293 }); 294 295 /** 296 * Unwraps .related-container and .custom-scrollbar elements from <strong> elements that may have been added by the CMS. 297 * This is a temporary fix until the CMS is fixed to not add these <strong> elements. We need to investigate WHY it does that to some stations... 298 * TODO: Remove this once the CMS is fixed/investigate 299 */ 300 301 function fixBrokenStationScrollContainer() { 302 const relatedContainers = $('.related-container'); 303 relatedContainers.each((_i, that) => { 304 if ($(that).parent().is('strong')) { 305 $(that).unwrap(); 306 } 307 }); 308 309 const $scrollbar = $('.custom-scrollbar'); 310 311 if ($scrollbar.parent().is('strong')) { 312 $scrollbar.unwrap(); 313 } 314 } 315}); 316 317let prevScrollpos = window.pageYOffset; 318let $scrolling = false; 319 320$(document).ready(function () { 321 handleDifferentBrowsers(); 322 removeUnscrollableScrollables(); 323 324 if (typeof $$epiforms !== 'undefined') { 325 $$epiforms(document).ready(function () { 326 $$epiforms('.EPiServerForms').on('formsSubmitted', 327 function (event) { 328 // const titleText = $($$epiforms(this).get(0)).children('.Form__Title').text(); 329 const form_name = location.pathname.replaceAll('/', '').replaceAll('-', '_'); 330 const success = event.isSuccess; 331 const form_id = `${$$epiforms(this).get(0).getAttribute('id')}`; 332 let error_msg = ''; 333 334 setTimeout(function () { 335 if (!success) { 336 error_msg = $('.Form__Element__ValidationError:visible').text(); 337 } 338 339 window.dataLayer = window.dataLayer || []; 340 window.dataLayer.push({ 341 event: 'form_submit', 342 form_name, 343 form_id, //Unikt id för formuläret, ska alltid vara samma id för samma formulär. 344 success, 345 error_msg 346 }); 347 }, 2000); 348 }); 349 }); 350 } 351 352 $(window).scroll(function () { 353 stickyHeader(); 354 });
355 356 SmoothScroll({ stepSize: 50 }); 357 358 $('#reg').on('keypress', stopSpacesInRegNr); 359 360 $('.block-start-products-plate-top-wrapper').matchHeight({ 361 byRow: true, 362 property: 'height', 363 target: null, 364 remove: false 365 }); 366 367 $('.block-text-on-image-wrapper').matchHeight({ 368 byRow: true, 369 property: 'height', 370 target: null, 371 remove: false 372 }); 373 374 $('#search404').on('click', function (e) { 375 const searchTerm = $('#input404').val(); 376 if(searchTerm.length < 3) { return; } 377 378 window.location= `/sok/?q=${searchTerm}`; 379 }); 380 381 $('#show-device-menu').on('click', function (e) { 382 e.preventDefault(); 383 const $this = $(this); 384 385 if ($this.hasClass('open')) { 386 $('#main').show(); 387 $('body').removeClass('menu-open'); 388 $this.removeClass('open'); 389 $('.device-header-menu').removeClass('open'); 390 $('.zoid-outlet').show(); 391 } else { 392 $('#main').hide(); 393 $('body').addClass('menu-open'); 394 $this.addClass('open'); 395 $('.device-header-menu').addClass('open'); 396 $('.zoid-outlet').hide(); 397 } 398 }); 399 400 $('.device-caret').on('click', function (e) { 401 e.preventDefault(); 402 const $this = $(this); 403 404 if ($this.hasClass('collapsed')) { 405 $this.removeClass('collapsed'); 406 $this.next().addClass('open'); 407 } else { 408 $this.addClass('collapsed'); 409 $this.next().removeClass('open'); 410 } 411 }); 412 413 $(document) 414 .on( 415 'mouseenter', 416 '.top-menu-item.has-children, .open > .mega', 417 function (event) { 418 hoverMenu(event, true); 419 } 420 ) 421 .on( 422 'mouseleave', 423 '.top-menu-item.has-children, .open > .mega', 424 function (event) { 425 hoverMenu(event, false); 426 } 427 ); 428 429 /** 430 * Removes scroll handle of scrollable containers that are not scrollable horizontally. 431 * If an container's scroll width is less than the document's width, the sibling element following its parent is removed 432 * (IE the scroll handle). 433 * It early exits if the first scrollable element has the class 'filters'. 434 */ 435 function removeUnscrollableScrollables() { 436 const scrollables = document.querySelectorAll('.scroll-content'); 437 438 scrollables.forEach((el) => { 439 const docWidth = el.closest('.bw-container').offsetWidth; 440 if (el.scrollWidth < docWidth && !el.className.includes('filters')) { 441 el.parentElement.nextElementSibling.remove(); 442 } 443 }); 444 } 445 446 function hoverMenu(event, isInside) { 447 const $menuItem = $(event.currentTarget); 448 const $currentTarget = $(event.relatedTarget); 449 if (isInside || $currentTarget.is('.top-nav, .mega')) { 450 $menuItem.parent().addClass('open'); 451 $('#menu-overlay').show(); 452 return; 453 } 454 $('#menu-overlay').hide(); 455 $menuItem.parent().removeClass('open'); 456 } 457 458 $(".mega-menu-toggler").on("click", function (e) { 459 e.preventDefault(); 460 const $this = $(this); 461 462 if (!$this.next().hasClass("closed")) { 463 $this.next().addClass("closed"); 464 $this.find(".mega-caret").addClass("collapsed"); 465 } else { 466 $this.next().removeClass("closed"); 467 $this.find(".mega-caret").removeClass("collapsed"); 468 } 469 }); 470 471 //$("#startblockbookingbutton").on("click", function (e) { 472 // e.preventDefault(); 473 // var reg = $("#reg").val(); 474 475 // if (isValidRegistrationNumber(reg)) { 476 // $("#startbookingform").submit(); 477 // } else { 478 // $("#errorwrapper").html("<div class=\"booking-alert\">Du har angivet ett felaktigt registreringsnummer</div>"); 479 // } 480 //}); 481 482 $(".close-global").on("click", function (e) { 483 e.preventDefault(); 484 var cookieName = "global-info"; 485 document.cookie = cookieName + "=true;path=/"; 486 $("#global-info").remove(); 487 });
488 489 $("#cookieacceptbutton").on("click", function (e) { 490 e.preventDefault(); 491 var aYearFromNow = new Date(); 492 aYearFromNow.setFullYear(aYearFromNow.getFullYear() + 1); 493 var dateAsString = aYearFromNow.toUTCString(); 494 var cookieName = "cookie-accept"; 495 document.cookie = cookieName + "=true; expires=" + dateAsString + ";path=/"; 496 $("#cookie-bar").remove(); 497 }); 498 499 $(document).on('click', ".faq-accordion-header", function (e) { 500 e.preventDefault(); 501 const $this = $(this); 502 503 if ($this.hasClass("collapsed")) { 504 $this.removeClass("collapsed"); 505 $this.next().addClass("open"); 506 } else { 507 $this.addClass("collapsed"); 508 $this.next().removeClass("open"); 509 } 510 }); 511 512 $(".station-show-more").on("click", function (e) { 513 e.preventDefault(); 514 e.stopPropagation(); 515 var $this = $(this); 516 var $that = $this.prev(); 517 518 if ($that.hasClass("open")) { 519 $that.removeClass("open"); 520 $this.removeClass("open"); 521 $this.text($this.data("open")); 522 } else { 523 $that.addClass("open"); 524 $this.addClass("open"); 525 $this.text($this.data("close")); 526 } 527 }); 528 529 $(".station-row-county-item").on("click", function (e) { 530 e.preventDefault(); 531 var $this = $(this); 532 var $target = $("#" + $this.data("target")); 533 534 if ($(window).outerWidth() < 1024) { 535 $target = $("#m_" + $this.data("target")); 536 $(".station-row-county-item-mobile").removeClass("open"); 537 } else { 538 $(".station-row-station-list-wrapper").removeClass("open"); 539 } 540 541 if (!$this.hasClass("open")) { 542 $(".footer").find(".station-row-county-item").removeClass("open"); 543 $(".footer").find(".station-row-station-list-wrapper").removeClass("open"); 544 $(".footer").find(".station-caret").addClass("collapsed"); 545 $this.addClass("open"); 546 $this.find(".station-caret").removeClass("collapsed"); 547 $target.addClass("open"); 548 549 $("html, body").animate({ 550 scrollTop: $this.offset().top 551 }, 600); 552 553 } else { 554 $this.removeClass("open"); 555 $this.find(".station-caret").addClass("collapsed"); 556 $target.removeClass("open"); 557 } 558 }); 559 560 if ($('#stationinputsearchpage').length > 0) { 561 562 var $stationSearch = $('#stationinputsearchpage'); 563 /* if (navigator.geolocation) { 564 navigator.geolocation.getCurrentPosition(showPosition); 565 }*/ 566 567 $("#stationsearchpage").on("click", function (e) { 568 e.preventDefault(); 569 if ($stationSearch.val().length > 1) { 570 $("#stationsearchform").submit(); 571 } 572 }); 573 574 $stationSearch.keyup(function (e) { 575 e.preventDefault(); 576 if (e.which === 13) { 577 if ($stationSearch.val().length > 1) { 578 $("#stationsearchform").submit(); 579 } 580 } 581 582 $('.station-search__result').css("width", $stationSearch.outerWidth()); 583 $("html, body").animate({ 584 scrollTop: ($stationSearch.offset().top - 80) 585 }, 600); 586 var temp = searchStation($stationSearch.val()); 587 $('.station-search__result').html(''); 588 var showMore = temp.length > 6; 589 var loopMax = 6; 590 if (temp.length < loopMax) { 591 loopMax = temp.length; 592 } 593 for (var i = 0; i < loopMax; i++) { 594 $('.station-search__result').append('<li><a href="' + temp[i].url + '"><div class="station-search__result-name text-lg">' + temp[i].title + '</div><div class="station-search__result-status' + '"></div></a></li>'); 595 } 596 if (showMore) { 597 $('.station-search__result').append('<li><a href="?sq=' + $stationSearch.val() + '"><div class="station-search__result-showall text-lg">VISA ALLA</div></a></li>'); 598 599 } 600 if ($('.station-search__result').html() === '') { 601 $('.station-search__result').append('<li class="text-lg><div class="station-search__notfound text-lg"><div>Tyvärr hittar vi ingen station som innehåller <strong>"' + $('<div/>').text($stationSearch.val()).html() + '"</strong></div>Kontrollera stavningen eller använd kartan för att hitta din närmsta Besikta-station.</div></li>'); 602 } 603 604 }); 605 606 $(".maps-use-geo").on("click", function (e) { 607 e.preventDefault(); 608 609 if (navigator.geolocation) { 610 navigator.geolocation.getCurrentPosition(showPosition); 611 } else { 612 $('.station-search__result').append('<li><div class="station-search__notfound"><div>Tyvärr stödjer inte din webbläsare geolocation</div></li>'); 613 } 614 }); 615 616 function showPosition(position) { 617 BesiktaMapHelper.updateListWithGeoInfo(position); 618 } 619 620 $('.station-input').blur(function () { 621 622 setTimeout(function () { 623 624 if ($('.station-search__result').html().indexOf('ajax-loader.gif') <= 0) { 625 $('.station-search__result').html(''); 626 } 627 628 }, 300); 629 }); 630 } 631 632 $("#bookingstartbutton").on("click", function (e) { 633 e.preventDefault(); 634 e.stopPropagation(); 635 if (isValidRegistrationNumber($("#reg").val())) { 636 $("#startbookingform").submit(); 637 } else { 638 $("#errorwrapper").html("<div class=\"booking-alert\">Du har angivet ett felaktigt registreringsnummer</div>"); 639 } 640 });
641 642 643 $(".block-station-services-item-header").on("click", function (e) { 644 var $this = $(this); 645 e.preventDefault(); 646 e.stopPropagation(); 647 if ($this.hasClass("collapsed")) { 648 $this.removeClass("collapsed"); 649 $this.next().removeClass("collapsed"); 650 651 } else { 652 $this.addClass("collapsed"); 653 $this.next().addClass("collapsed"); 654 655 } 656 }); 657 658 calculateBookingButtonWidth(); 659 660 if (location.hash.length > 0) { 661 var loc = $(location.hash); 662 if (loc.length !== 0) { 663 $('html, body').animate({ 664 'scrollTop': $(location.hash).offset().top - 100 665 }, 666 200); 667 } 668 } 669}); 670 671function stopSpacesInRegNr(keypress) { 672 if (keypress.which === 32) { 673 return false; 674 } 675} 676 677var BesiktaMapHelper = { 678 updateListWithGeoInfo: function (position) { 679 var temp = getNearestStation(position.coords.latitude, position.coords.longitude); 680 681 $('.station-search__result').css("width", $('.station-input').outerWidth()); 682 $("html, body").animate({ 683 scrollTop: ($('.station-input').offset().top - 80) 684 }, 600); 685 686 $('.station-search__result').html(''); 687 for (var i = 0; i < temp.length; i++) { 688 $('.station-search__result').append('<li><a href="' + temp[i].url + '"><div class="station-search__result-name">' + temp[i].title + '</div><div class="station-search__result-status open-' + temp[i].dropin + '"></div></a></li>'); 689 } 690 $(".maps-use-geo").addClass("active"); 691 $('.station-input').focus(); 692 }, 693 getDistanceFromLatLonInKm: function (lat1, lon1, lat2, lon2) { 694 var R = 6371; // Radius of the earth in km 695 var dLat = this.deg2rad(lat2 - lat1); // deg2rad below 696 var dLon = this.deg2rad(lon2 - lon1); 697 var a = 698 Math.sin(dLat / 2) * Math.sin(dLat / 2) + 699 Math.cos(this.deg2rad(lat1)) * Math.cos(this.deg2rad(lat2)) * 700 Math.sin(dLon / 2) * Math.sin(dLon / 2) 701 ; 702 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 703 var d = R * c; // Distance in km 704 return d; 705 }, 706 deg2rad: function (deg) { 707 return deg * (Math.PI / 180); 708 } 709} 710 711function calculateBookingButtonWidth() { 712 const headerWrapper = $('#header > .main-wrapper'); 713 const leftHeader = $('.header-left'); 714 const bookingButton = $('#bookmainbutton'); 715 const rightSpace = headerWrapper.width() - leftHeader.width(); 716 let newPadding = ''; 717 718 if (rightSpace < 170) { 719 bookingButton.html('Boka besiktning'); 720 const buttonWidth = bookingButton.outerWidth(); 721 722 if (buttonWidth > rightSpace) { 723 const paddingToRemove = Math.ceil((buttonWidth - rightSpace) / 2); 724 const sidePadding = parseInt(bookingButton.css('padding-left')); 725 newPadding = sidePadding - paddingToRemove; 726 } 727 } else { 728 const btnImageHtml =$('#bookmainbutton > img')[0]; 729 730 if (btnImageHtml !== undefined) { 731 bookingButton.html('Boka besiktning'); 732 } 733 } 734 bookingButton.css('padding-inline', newPadding); 735} 736 737$(window).bind('load resize orientationchange', function () { 738 stickyHeader(); 739 calculateBookingButtonWidth(); 740 741 if ($(window).outerWidth() > 1024) { 742 $('#main').show(); 743 $('body').removeClass('menu-open'); 744 $('#show-device-menu').removeClass('open'); 745 $('.device-header-menu').removeClass('open'); 746 } 747}); 748 749 750$(document).on('click', '.footer-station-toggler-wrapper .footer-station-toggler', {}, function (e) { 751 e.preventDefault(); 752 var $this = $(this); 753 var stations = $(".footer-station-toggler-wrapper").find(".footer-station-toggler"); 754 $(".footer-station-toggler-wrapper").find(".station-row-result").removeClass("active"); 755 var $that = $("#stat_" + $this.data("stationid")); 756 $that.insertAfter($(stations[stations.length])); 757 if ($(window).outerWidth() < 1024) { 758 $that.insertAfter($(stations[$this.data("stationindex")])); 759 } else if ($(window).outerWidth() < 1200 && $(window).outerWidth() >= 1024) { 760 var ind = ($this.data("stationindex") + 1); 761 if (ind !== stations.length) { 762 if ((ind % 2 === 0) === false) { 763 for (var i = 0; i <= 1; i++) { 764 ind = (($this.data("stationindex") + 1) + i); 765 if ((ind % 2 === 0) === true) { 766 break; 767 } 768 } 769 } 770 } 771 $that.insertAfter($(stations[ind - 1])); 772 773 } else { 774 var ind = ($this.data("stationindex") + 1); 775 if (ind !== stations.length) { 776 if ((ind % 4 === 0) === false) { 777 for (var i = 0; i <= 3; i++) { 778 ind = (($this.data("stationindex") + 1) + i); 779 if ((ind % 4 === 0) === true) { 780 break; 781 } 782 } 783 } 784 } 785 $that.insertAfter($(stations[ind - 1])); 786 } 787 788 if ($this.hasClass("open")) { 789 $this.removeClass("open"); 790 $this.find(".station-caret").addClass("collapsed"); 791 $that.html(''); 792 $that.removeClass("active"); 793 } else { 794 $this.parent().find(".open").removeClass("open"); 795 $this.parent().find(".station-caret").addClass("collapsed"); 796 $this.addClass("open"); 797 $this.find(".station-caret").removeClass("collapsed"); 798 799 $that.addClass("active"); 800 } 801}); 802 803function stickyHeader() { 804 const currentScrollPos = window.pageYOffset; 805 if ($scrolling === false) { 806 if ($(window).outerWidth() > 768) { 807 const $header = $("#header"); 808 if ($header !== null) { 809 if (window.pageYOffset > 175) { 810 if (prevScrollpos >= currentScrollPos) { 811 $header.removeClass("hide-header"); 812 if (window.pageYOffset > 175) { 813 $header.addClass("scroll-header"); 814 } else { 815 $header.removeClass("scroll-header"); 816 } 817 } else { 818 $header.addClass("hide-header"); 819 } 820 } else { 821 $header.removeClass("hide-header"); 822 $header.removeClass("scroll-header"); 823 } 824 } 825 } else { 826 const $deviceheader = $(".device-header"); 827 if ($deviceheader !== null) { 828 if (window.pageYOffset > 70) { 829 if (prevScrollpos >= currentScrollPos) { 830 $deviceheader.removeClass("hide-header"); 831 if (window.pageYOffset > 70) { 832 $deviceheader.addClass("scroll-header"); 833 } else { 834 $deviceheader.removeClass("scroll-header"); 835 } 836 } else { 837 $deviceheader.addClass("hide-header"); 838 } 839 } else { 840 $deviceheader.removeClass("hide-header"); 841 $deviceheader.removeClass("scroll-header"); 842 } 843 } 844 } 845 } 846 prevScrollpos = currentScrollPos; 847} 848 849function isValidEmailAddress(emailAddress) { 850 var pattern = /^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([ \t]*\r\n)?[ \t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([ \t]*\r\n)?[ \t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i; 851 return pattern.test(emailAddress); 852}; 853 854function isValidRegistrationNumber(reg) { 855 var pattern = /[A-Za-z]{3}[0-9]{2}[A-Za-z0-9]{1}/g; 856 return pattern.test(reg); 857};
858 859function isValidMobile(mobile) { 860 mobile = mobile.replace(/ /g, ''); 861 mobile = mobile.replace(/-/g, ''); 862 var pattern = /^([+]46)\s*(7[02369])\s*(\d{4})\s*(\d{3})$/i; 863 if (pattern.test(mobile)) { 864 return true; 865 } 866 pattern = /^s*(07[02369])\s*(\d{4})\s*(\d{3})$/i; 867 if (pattern.test(mobile)) { 868 return true; 869 } 870 pattern = /^s*(0[{1-9}])\s*(\d{5,10})$/i; 871 if (pattern.test(mobile)) { 872 return true; 873 } 874 pattern = /^([+]46)\s*(\d{7,10})$/i; 875 return pattern.test(mobile); 876}; 877 878function strip(html) { 879 var tmp = document.createElement("DIV"); 880 tmp.innerHTML = html; 881 return tmp.textContent || tmp.innerText || ""; 882} 883 884if (!String.prototype.includes) { 885 String.prototype.includes = function (search, start) { 886 'use strict'; 887 888 if (search instanceof RegExp) { 889 throw TypeError('first argument must not be a RegExp'); 890 } 891 if (start === undefined) { start = 0; } 892 return this.indexOf(search, start) !== -1; 893 }; 894} 895 896function loadPartialPage(path) { 897 fetch(path) 898 .then((response) => response.text()) 899 .then((html) => { 900 $("#partialload").html(html); 901 }) 902 .catch((error) => { 903 }); 904} 905 906function handleDifferentBrowsers() { 907 // Conditional IE10 and IE11 handling. 908 var UAString = navigator.userAgent; 909 var isSafari = /^((?!chrome|android).)*safari/i.test(UAString); 910 911 if (UAString.indexOf('MSIE 10') !== -1) { 912 document.documentElement.setAttribute('data-ie', 'MSIE10'); 913 } 914 915 if (UAString.indexOf('Trident') !== -1 && UAString.indexOf('rv:11') !== -1) { 916 document.documentElement.setAttribute('data-ie', 'MSIE11'); 917 } 918 919 if (isSafari) { 920 document.documentElement.setAttribute('data-ie', 'Safari'); 921 } 922 923 if(document.documentElement.getAttribute('data-ie')){ 924 $('[data-ieimg]').each(function () { 925 const $this = $(this); 926 $this.attr('style','background-image:url(' + $this.data('ieimg') + ');'); 927 }); 928 } 929} 930 931//add rel attributes to all links that open a new tab 932window.addEventListener("load", () => 933 [...document.querySelectorAll("a[target=_blank]")] 934 .forEach(lnk => lnk.setAttribute("rel", "noopener noreferrer")) 935); 936 937/* Start booking block start */ 938$(document).on('click', '#startblockbookingbutton', {}, function (e) { 939 e.preventDefault(); 940 e.stopPropagation(); 941 var reg = $("#reg").val(); 942 var bsi = $("#bsi").val(); 943 var camp = $("#campaign").val(); 944 if (isValidRegistrationNumber(reg)) { 945 var postData = {}; 946 postData["reg"] = reg; 947 postData["bsi"] = bsi; 948 postData["camp"] = camp; 949 950 $.ajax({
951 contentType: "application/json; charset=utf-8", 952 data: JSON.stringify(postData), 953 dataType: "json", 954 url: "/Service/ValidateBookingStart", 955 type: "post", 956 cache: false, 957 success: function (data) { 958 if (data.success) { 959 location.href = data.url + "?bsi=" + bsi + "®=" + reg + "&campaign=" + camp; 960 } else { 961 $("#errorwrapper").html("<div class=\"booking-alert\">NÃ¥got gick fel</div>"); 962 } 963 }, 964 error: function () { 965 $("#errorwrapper").html("<div class=\"booking-alert\">NÃ¥got gick fel</div>"); 966 } 967 }); 968 } else { 969 $("#errorwrapper").html("<div class=\"booking-alert\">Du har angivet ett felaktigt registreringsnummer</div>"); 970 } 971}); 972 973$(document).on('keydown', '#reg', {}, function (e) { 974 if (e.keyCode === 13) { 975 $('#startblockbookingbutton').click(); 976 } 977}); 978/* Start booking block stop */ 979 980/* This view acts as a rendering template to render InitScript(and server-side Form's descriptor) in FormContainerBlock's client-side for Form[75a6fb6d-5908-4afa-9caf-99d6a4489d26]. 981TECHNOTE: all serverside (paths, dynamic values) of EPiServerForms will be transfered to client side here in this section. */ 982(function initializeOnRenderingFormDescriptor() { 983 if (typeof epi === 'undefined') { return; } 984 // each workingFormInfo is store inside epi.EPiServer.Forms, lookup by its FormGuid 985 var workingFormInfo = epi.EPiServer.Forms["75a6fb6d-5908-4afa-9caf-99d6a4489d26"] = { 986 Id: "75a6fb6d-5908-4afa-9caf-99d6a4489d26", 987 Name: "Registreringsbesiktning - Bokning", 988 // whether this Form can be submitted which relates to the visitor's data (cookie, identity) and Form's settings (AllowAnonymous, AllowXXX) 989 990 SubmittableStatus: { "submittable": true, "message": "" }, 991 ConfirmMessage: "Tack! Vi kommer att svara dig inom kort.", 992 ShowNavigationBar: false, 993 ShowSummarizedData: false, 994 995 // serialize the dependency configuration of this form to clientside 996 DependenciesInfo: [], 997 // keep all fieldName which are not satisfied the field dependency conditions 998 DependencyInactiveElements: [], 999 1000 // Validation info, for executing validating on client side 1001 ValidationInfo: [{ "targetElementName": "__field_1418", "targetElementId": "d7dc1a5d-ebc4-4a7f-bfd4-2ae24943c950", "validators": [{ "type": "EPiServer.Forms.Implementation.Validation.RequiredValidator", "description": null, "model": { "message": "Fältet är obligatoriskt.", "validationCssClass": "ValidationRequired", "additionalAttributes": { "required": "", "aria-required": "true" } } }] }, { "targetElementName": "__field_1416", "targetElementId": "bf5b4e06-d13d-46ca-93f2-75b290b95bea", "validators": [{ "type": "EPiServer.Forms.Implementation.Validation.RequiredValidator", "description": null, "model": { "message": "Fältet är obligatoriskt.", "validationCssClass": "ValidationRequired", "additionalAttributes": { "required": "", "aria-required": "true" } } }
1001, { "type": "EPiServer.Forms.Implementation.Validation.EmailValidator", "description": null, "model": { "jsPattern": "(^$)|(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)", "dotNetPattern": "(^$)|(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)", "message": "Ange en giltig e-postadress.", "validationCssClass": null, "additionalAttributes": null } }] }, { "targetElementName": "__field_1417", "targetElementId": "f0c7d112-a0e4-4f6d-a76c-48be9ed423d4", "validators": [{ "type": "EPiServer.Forms.Implementation.Validation.RequiredValidator", "description": null, "model": { "message": "Fältet är obligatoriskt.", "validationCssClass": "ValidationRequired", "additionalAttributes": { "required": "", "aria-required": "true" } } }] }, { "targetElementName": "__field_1415", "targetElementId": "dcf6f1ca-4589-466e-88b3-1558fa200857", "validators": [{ "type": "EPiServer.Forms.Implementation.Validation.RequiredValidator", "description": null, "model": { "message": "Fältet är obligatoriskt.", "validationCssClass": "ValidationRequired", "additionalAttributes": { "required": "", "aria-required": "true" } } }] }], 1002 // Steps information for driving multiple-step Forms. 1003 StepsInfo: { 1004 Steps: [{ "index": 0, "attachedUrl": "", "dependField": null, "dependCondition": null, "isActive": true, "attachedContentLink": "", "dependValue": "", "elementName": "__field_", "guid": "00000000-0000-0000-0000-000000000000" }] 1005 }, 1006 FieldsExcludedInSubmissionSummary: [], 1007 ElementsInfo: { "__field_1418": { "type": "EPiServer.Forms.Implementation.Elements.TextboxElementBlock", "friendlyName": "Namn", "customBinding": false }, "__field_1420": { "type": "EPiServer.Forms.Implementation.Elements.TextboxElementBlock", "friendlyName": "Telefonnummer", "customBinding": false }, "__field_1416": { "type": "EPiServer.Forms.Implementation.Elements.TextboxElementBlock", "friendlyName": "E-post", "customBinding": false }, "__field_1417": { "type": "EPiServer.Forms.Implementation.Elements.TextboxElementBlock", "friendlyName": "Stad", "customBinding": false }, "__field_1415": { "type": "EPiServer.Forms.Implementation.Elements.TextboxElementBlock", "friendlyName": "Regnr eller ärendenr", "customBinding": false }, "__field_1421": { "type": "EPiServer.Forms.Implementation.Elements.TextareaElementBlock", "friendlyName": "Beskrivning av ärende", "customBinding": false }, "__field_1419": { "type": "EPiServer.Forms.Implementation.Elements.SubmitButtonElementBlock", "friendlyName": "Skickaknapp", "customBinding": false } }, 1008 DataSubmitController: "/EPiServer.Forms/DataSubmit" 1009 1010 }; 1011 1012 /// TECHNOTE: Calculation at FormInfo level, and these values will be static input for later processing. 1013 workingFormInfo.StepsInfo.FormHasNoStep_VirtualStepCreated = true; // this FLAG will be true, if Editor does not put any FormStep. Engine will create a virtual step, with empty GUID 1014 workingFormInfo.StepsInfo.FormHasNothing = false; // this FLAG will be true if FormContainer has no element at all 1015 workingFormInfo.StepsInfo.AllStepsAreNotLinked = true; // this FLAG will be true, if all steps all have contentLink=="" (emptyString) 1016})();
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.