{"version":3,"mappings":"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","names":["verifyPropertyExists","obj","current","rest","configuration","GoogleTagManager","#dataLayer","eventName","params","TagManager","initFormBlockBase","handleFormsNavigateToStep","handleFormsStartSubmitting","handleFormsSubmitted","event","form","stepContainer","currentLabel","doneLabel","stepList","currentIndex","stepElements","stepElement","isCurrentStep","stepStateElement","isDoneStep","formElement","hiddenElement","hiddenElementName","formType","properties","getFormProperties","handleBookShowingLead","formContainer","formLeadType","formStepIndex","getCurrentStepIndex","formStep","workingFormGuid","workingFormInfo","checkIfBookShowingFormSentLead","formData","currentForm","elementsInfo","key","sendLeadsFormFriendlyName","sendLeadsFormElementInfo","x","initFriendlyCaptcha","WidgetInstance","friendlyCaptchaElements","friendlyCaptchaElement","siteKey","targetElementId","targetElement","submitButton","puzzleEndpoint","__vitePreload","widget","token","e","VimeoVideo","#vimeoId","vimeoId","parseResult","vimeoIdOrUrl","match","autoplay","response","cachePrefix","pruneCache","now","expiresAt","readFromCache","data","writeToCache","expireInMinutes","getThumbnailUrl","vimeoVideo","cacheKey","cachedThumbnailUrl","thumbnailUrl","initGuideBlocks","rootElement","blocks","block","setupBlock","videoSection","videoSrc","insertThumbnailImage","setupEventHandlers","container","img","createPlayer","closeOverlay","destroyPlayer","hideStaticElements","openOverlay","iframeContainer","loader","iframe","messageCallback","message","showStaticElements","initBlocks","self","Object","wm","create","defineProperty","proto","EventTarget","define","type","listener","options","secret","listeners","i","length","dispatch","target","name","value","info","EventTarget$1","ScrollManager","#scrolledElement","#measuredElement","#lastScrollPosition","#lastSwitchPosition","#scrollDirection","#boundOnScroll","scrolledElement","measuredElement","#onScroll","scrollTop","#recordScrollPosition","scrollPosition","lastPosition","lastScrollDirection","scrollDirection","firstAnscestorOrDefault","element","predicate","includeSelf","parent","intersectionObserver","scrollManager","applyAnchorContainer","containerElements","destroy","containerElement","initAnchorContainer","anchorList","anchorItem","anchorItems","anchorLinks","anchorLink","anchorListItem","list","makeSticky","initIntersectionObserver","stickyElement","alreadySticky","breakpoint","scrollEvent","scrolledDistance","showAfter","hideAfter","entries","entry","anchorLinkId","updateAnchorListScrollPosition","anchorContainer","actualList","currentAnchors","anchor","anchorOffsetLeft","applyAnimations","setupEnterScreenAnimations","setupHeroAnimations","setupBrokerProfileAnimations","elementsToFadeUpOnEnterScreen","triggerOnEnterScreen","animate","hero","heading","ingress","interactionContainer","brokerPageProfile","brokerProfileHeading","brokerProfileInfo","index","animation","delay","enterScreenCallback","elements","enterScreenObserver","apply","videos","video","ME_SECONDARY_BUTTON","handleClick","clickedElement","clickTargetAncestor","clickIgnoreAncestor","ownerElement","clickTarget","newEvent","COOKIE_TRACTOR_SCROLL_LOCK_CLASS","applyCookieTractor","handleCookieTractorScrollLock","mutations","mutation","eventHandler","isContactLink","contactType","href","escapeStringRegexp","string","SPACE_KEY","Combobox","#comboboxElement","#listboxElement","#selectedIndex","#isOpen","comoboxElement","listboxElement","#setupEventListeners","#visibleListboxItems","#listboxItems","#listboxGroups","#isMultiselect","#isDisabled","#supportsFiltering","comboboxElement","#handleKeyDown","#updateARIAAttributes","newFocus","#reset","#handleOptionClick","#handleFilterInput","#updateVisibilityAttributes","#updateScrollPosition","suggestions","newIndex","#handleEnterKey","filterText","items","hasFilterText","filterRegex","item","text","matches","itemGroups","group","visibleItems","clickedItem","#handleItemSelectedEvent","selectedIndex","selecteditem","itemElement","isSelected","selectedItem","scrollHeight","listboxHeight","itemTop","itemBottom","listboxBottom","showPanel","url","overlayElements","overlayElement","debounce","func","timeout","timer","args","this","calculateButtonVisibility","button","content","contentHeight","contentScrollHeight","initAccordions","accordions","accordion","initObserver","node","accordionElement","accordionContainer","isExpanded","Postbox","postbox","handleKeydown","isInTablist","tablist","getTablist","handled","selectPreviousTab","selectNextTab","selectTab","getFirstTab","getLastTab","tab","getCurrentTab","getCurrentTabPanel","currentTab","tabId","tabs","getNextTab","nextSibling","getPreviousTab","previousSibling","skipFocus","panel","currentPanel","previousTab","nextTab","isIgnoredElement","attributes","attribute","getTargetElement","toggledElement","targetSelector","getSynchronizedElements","toggleElementClassesOnTargets","targetElements","setOpenClass","targetClassName","toggleElementClassesOnSources","sourceElements","sourceElement","attributeNames","elementsToSynchronize","focusId","focusElement","scrollToId","initPageScripts","applyAutoPlayVideo","applyClickableContainers","applyGoogleTagManagerEvents","applyLanguageSelectors","applyOverlayScripts","applyReadMoreAccordion","applyStickyHeader","applyTabs","applyToggleOpen","getPageLanguage","fallback","SEARCH_DEBOUNCE_TIMEOUT","LOADER_TIMEOUT","initBrokerSearchPage","pageElement","initSearchForm","searchForm","searchInput","resetLink","regionContainer","getSelectedRegion","searchTerm","region","debouncedPerformSearch","performSearch","regionFilters","doneLoading","insertLoader","updateUrl","html","fetchResults","insertErrorMessage","destroyAnchorContainer","resultsContainer","initializeAnchorContainer","errorMessage","abortController","signal","error","BiddingRefreshIntervalInMilliseconds","updateHandle","loading","updateBiddingInformation","pageLanguage","estateId","biddingHtml","biddingDialogContent","bidContainer","currentScrollPosition","dialogOpened","dialog","dialogClosed","initBiddingDialog","initBookShowingDialog","targetShowingId","preselectOption","officeID","selectFriendlyName","targetOptionValue","selectElementInfo","selectElement","targetOption","initFactsSection","factsRoot","listItem","toggleElement","hiddenElements","factsElement","initImageDialog","selectTabId","scrollAnchor","targetImage","dialogContent","initProjectEstates","projectEstatesContainer","showAllProjectestatesButton","culture","estateShortId","tableBody","row","initSimilarEstates","similarEstatesContainer","initEstatePage","generateUUID","char","allowedYValues","array","MINIMUM_NUMBER_OF_CHARS","FreetextAutocompleteCombobox","#abortController","#debouncedFetchAutocomplete","#fetchSuggestions","#init","result","#updateSuggestions","#handleItemSelected","addFilterEvent","callback","suggestion","#renderSuggestions","getPriceText","estateLink","formattedPrice","address","price","isNullOrWhiteSpace","input","SearchFormHandler","#form","#currentPageIndex","#currentPageSize","#handleFormSubmit","#handleRequestNextPage","#getCleanFormData","#updateRestoreToQueryString","pageIndex","pageSize","restoreUrl","#buildUrl","#updateUrl","state","title","keys","baseUrl","urlParts","querystring","#toQueryString","estateType","estateTypeElement","label","SwedishSearchFormHandler","SearchFormHandlerBase","#autocompleteHandler","#geographicalFilterContainer","#geographicalFilterTemplate","autocompleteHandler","#addGeographicalFilter","#handleGeographialFilterRemoval","field","labelValue","existingFilters","filter","templateRoot","inputValue","inputLabel","span","checkbox","comingSoonSelect","#getMunicipalityForUrl","#getAreaForUrl","municipalityId","areaId","initSwedishSearchForm","combobox","listbox","comparerCache","getComparer","locale","comparer","localeCompareSupportsLocales","localeComparer","a","b","shouldWarn","asciiStrings","asciiRegex","InternationalAreaCombobox","#inputContainerElement","#disabled","inputContainerElement","multiselectOptionId","#dispatchChangeEvent","filterField","filterLabel","filterValue","selectedOptionsList","language","insertAtIndex","option","textContent","optionId","#createItemGroups","groups","templateElement","#createItemsInGroup","groupElement","#updateDisabledAttributes","disabled","selectedOptions","selectedOption","CountrySelectWrapper","#selectElement","#hiddenFallbackElement","hiddenFallbackElement","#handleSelectChange","seletedOption","InternationalSearchFormHandler","#multiselects","multiselects","#updateAvailability","#fetchNewSuggestions","#handleReferenceNumberButtonClick","errorMessageElement","referenceNumber","#getCountryForUrl","#getGeographicalFiltersForUrl","province","#getGeographicalFilterlabel","city","cityArea","selectedInput","#getFormData","queryFields","dependsOn","initInternationalSearchForm","countrySelectElement","countrySelect","provinceComboboxElement","provinceCombobox","getCombobox","getComboboxContainerElement","cityComboboxElement","cityCombobox","cityAreaComboboxElement","cityAreaCombobox","CreateSearchAlertButtonHandler","#button","#handleToggleEvent","enableButton","disabledTooltip","SearchResultHandler","#container","#resultsList","#resultInfo","#loader","#showMoreContainer","#handleQueryChangedBound","#debouncedFetchResults","#fetchResult","#intersectionObserver","#handleQueryChanged","#initMoreResultsButton","#initIntersectionObserver","hideStickyInfo","classNames","#fetchNextPage","query","#updateResults","#showMoreResultsButton","#disableSortSelect","show","disable","sortSelect","tempContainer","listItems","resultsInfo","initEstateSearchPage","initPages","focusedContainer","lockFocus","focusHandler","unlockFocus","lockScroll","unlockScroll","Dialog","#targetElement","#openedFromElement","#handleClickBound","#handleKeyDownBound","#handleClick","#initElements","header","#generateUniqueElementId","activatorElements","#getActivatorElements","#updateElements","isOpen","activatorElement","baseId","id","#getCloseButtons","DialogManager","#dialogs","#registerDialogs","dialogElements","elementWithDialogActivator","activatorElementId","dialogElement","closeElementId"],"ignoreList":[10,19],"sources":["../../../SkandiaMaklarna.Web.Frontend/scripts/utils/verify-property-exists.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/configuration.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/google-tag-manager.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/block-scripts/form-blocks.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/block-scripts/forms/friendly-captcha.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/vimeo-video.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/local-cache.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/vimeo-thumbnail-cache.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/block-scripts/guide-block.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/block-scripts/init.mjs","../../../SkandiaMaklarna.Web.Frontend/node_modules/@ungap/event-target/esm/index.js","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/scroll-manager.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/dom-utils.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/anchor-container.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/animate.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/autoplay-video.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/clickable-containers.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/cookie-tractor.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/google-tag-manager-events.mjs","../../../SkandiaMaklarna.Web.Frontend/node_modules/escape-string-regexp/index.js","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/combobox.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/language-selector.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/overlays.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/debounce.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/read-more-accordion.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/sticky-header.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/postbox.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/tabs.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/toggle-open.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/page-scripts/init.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/get-page-language.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/broker-search-page.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page/bidding-dialog.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page/book-showing-dialog.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page/facts.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page/image-dialog.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page/project-estates.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page/similar-estates.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-page.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/generate-uuid.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/freetext-autocomplete-combobox.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/string-utils.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/search-form-handler-base.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/swedish-search-form-handler.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/swedish-search-form.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/locale-comparer.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/international-area-combobox.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/country-select-wrapper.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/international-search-form-handler.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/international-search-form.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/create-search-alert-button-handler.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page/search-result-handler.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/estate-search-page.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/pages/init.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/lock-focus.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/scroll-utils.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/dialog.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/utils/dialog-manager.mjs","../../../SkandiaMaklarna.Web.Frontend/scripts/index.mjs"],"sourcesContent":["/**\n * Verifies that a property exists deep down on an object\n * @param {object} obj The root object to check from\n * @param {string} current The first property name to check\n * @param {...string} rest The rest of the property names to check\n * @returns {boolean} True if the property exists, false otherwise\n */\nexport let verifyPropertyExists = (obj, current, ...rest) => {\n if(typeof obj === 'undefined') {\n return false;\n }\n\n if(rest.length === 0 && Object.prototype.hasOwnProperty.call(obj, current)) {\n return true;\n }\n\n return verifyPropertyExists(obj[current], ...rest);\n};\n","/**\n * Global configuration object generated through SiteConfigurationTagHelper\n * @typedef {object} SiteConfiguration\n * @property {string} culture The culture of the current page.\n * @property {string} environment The current environment for the site such as Development, Integration, Preproduction and Production.\n * @property {('Sweden'|'International')} website The current website.\n * @property {EstateConfiguration} estate Information about the current estate.\n * @property {OfficeConfiguration} office Information about the current office.\n * @property {BrokerConfiguration} broker Information about the current broker.\n * @property {FriendlyCaptchaConfiguration} friendlyCaptcha Friendly Captcha configuration.\n */\n\n/**\n * @typedef {object} EstateConfiguration\n * @property {string} id The id of the current estate.\n * @property {number} shortId The short id of the current estate.\n * @property {boolean} showBids Whether or not bids should be shown for the current estate.\n */\n\n/**\n * @typedef {object} OfficeConfiguration\n * @property {string} id The id of the current office.\n * @property {string} name The name of the current office.\n */\n\n/**\n * @typedef {object} BrokerConfiguration\n * @property {string} id The id of the current office.\n * @property {string} name The name of the current office.\n */\n\n/**\n * @typedef {object} FriendlyCaptchaConfiguration\n * @property {string} siteKey The site key for Friendly Captcha.\n * @property {boolean} useEUEndpoint If true puzzles should be requested from the EU endpoint.\n */\n\n/** @type {SiteConfiguration} */\nexport default {\n estate: {},\n broker: {},\n office: {},\n friendlyCaptcha: {},\n ...window.siteConfiguration\n};\n","export class GoogleTagManager {\n #dataLayer;\n\n constructor() {\n this.#dataLayer = window.dataLayer || (window.dataLayer = []);\n }\n\n /**\n * @param {string} eventName The camelCased name of the event\n * @param {{[key: string]: string|number}} params The parameters to send with the event\n */\n trackEvent(eventName, params) {\n this.#dataLayer.push({\n event: eventName,\n ...params\n });\n }\n}\n\nexport default new GoogleTagManager();\n","/* global $$epiforms */\nimport { verifyPropertyExists } from '../utils/verify-property-exists.mjs';\nimport configuration from '../configuration.mjs';\nimport TagManager from '../utils/google-tag-manager.mjs';\n\nexport default () => {\n if(typeof $$epiforms === 'function') {\n $$epiforms(document).ready(() => {\n $$epiforms('.EPiServerForms').on('formsNavigateToStep', handleFormsNavigateToStep);\n $$epiforms('.EPiServerForms').on('formsStartSubmitting', handleFormsStartSubmitting);\n $$epiforms('.EPiServerForms').on('formsSubmitted', handleFormsSubmitted);\n });\n }\n\n // Disable the form scrolling to the top after every step\n if(verifyPropertyExists(window, 'epi', 'EPiServer', 'Forms', 'Utils', 'scrollToTheTopOfForm')) {\n window.epi.EPiServer.Forms.Utils.scrollToTheTopOfForm = () => { };\n }\n\n // Enable async submit for forms\n if(verifyPropertyExists(window, 'epi', 'EPiServer', 'Forms')) {\n window.epi.EPiServer.Forms.AsyncSubmit = true;\n }\n};\n\nexport const handleFormsNavigateToStep = event => {\n const form = event.currentTarget;\n const stepContainer = form.previousElementSibling;\n if(stepContainer?.matches('.step-container') !== true) {\n console.warn('Could not find step container for form', form);\n return;\n }\n\n const currentLabel = stepContainer.dataset.currentLabel;\n const doneLabel = stepContainer.dataset.doneLabel;\n\n const stepList = stepContainer.querySelector('ol');\n\n const currentIndex = event.targetStep.index;\n const stepElements = [...stepList.children];\n for(const stepElement of stepElements) {\n const isCurrentStep = stepElements.indexOf(stepElement) === currentIndex;\n stepElement.classList.toggle('current', isCurrentStep);\n\n const stepStateElement = stepElement.querySelector('.step-state');\n if(!stepStateElement) {\n continue;\n }\n\n const isDoneStep = stepElements.indexOf(stepElement) < currentIndex;\n if(isCurrentStep) {\n stepStateElement.textContent = currentLabel;\n } else if(isDoneStep) {\n stepStateElement.textContent = doneLabel;\n } else {\n stepStateElement.textContent = '';\n }\n }\n};\n\nexport const handleFormsStartSubmitting = event => {\n if(!verifyPropertyExists(window, 'epi', 'EPiServer', 'Forms')) {\n return;\n }\n\n const formElement = event.currentTarget;\n\n if(!formElement) {\n return;\n }\n\n const hiddenElement = formElement.querySelector(`input[data-search-query-element]`);\n\n if(!hiddenElement) {\n return;\n }\n\n // This is somewhat of a workaround to get the field name for the search query\n // element since hiddens elements for some reason are not included in the\n // elementInfo data.\n const hiddenElementName = hiddenElement.getAttribute('name');\n event.formData.set(hiddenElementName, window.location.search);\n};\n\nexport const handleFormsSubmitted = event => {\n const [formType, properties] = getFormProperties(event);\n\n if(!formType) {\n return;\n }\n\n if(!!properties.formStep) {\n TagManager.trackEvent(`${formType}-form-step-${properties.formStep}`, properties);\n }\n\n if(event.isFinalizedSubmission) {\n TagManager.trackEvent(`${formType}-form`, properties);\n\n // Book showing form can also send a lead in some cases\n // In that case we want to track that as well\n if(formType === 'book-showing') {\n handleBookShowingLead(formContainer, event.formData);\n }\n }\n};\n\n/**\n * @param {Event} event The event\n * @returns {[string, Object]} The form type and the properties\n */\nexport const getFormProperties = (event) => {\n const formElement = event.currentTarget;\n if(!formElement) {\n return [null, null];\n }\n\n\n if(!formElement) {\n return [null, null];\n }\n\n const formContainer = formElement.closest('.form-container');\n\n if(!formContainer) {\n return [null, null];\n }\n\n const formType = formContainer.dataset.formType ?? 'unknown';\n const formLeadType = formContainer.dataset.formLeadType;\n\n const formStepIndex = getCurrentStepIndex(formElement);\n const formStep = formStepIndex !== undefined ? formStepIndex + 1 : undefined;\n\n const properties = {\n officeId: configuration.office?.id,\n officeName: configuration.office?.name,\n brokerId: configuration.broker?.id,\n brokerName: configuration.broker?.name,\n estateId: configuration.estate?.id,\n estateShortId: configuration.estate?.shortId,\n culture: configuration.culture,\n leadType: formLeadType,\n formStep: formStep\n };\n\n return [formType, properties];\n};\n\n/**\n * @param {HTMLElement} formElement The form element\n * @returns {number} The current step index, or undefined if not found\n */\nexport const getCurrentStepIndex = formElement => {\n const workingFormGuid = formElement.id;\n\n const workingFormInfo = window.epi.EPiServer.Forms[workingFormGuid];\n workingFormInfo.$workingForm = $$epiforms(formElement);\n\n return window.epi.EPiServer.Forms.Utils.getCurrentStepIndex(workingFormInfo);\n};\n\n/**\n * @param {HTMLElement} formContainer The form container\n * @param {FormData} formData The sent form data\n * @returns {boolean} True if the form sent a lead, false otherwise\n */\nexport const checkIfBookShowingFormSentLead = (formContainer, formData) => {\n if(!formContainer || formContainer.dataset.formType !== 'book-showing') {\n return false;\n }\n\n const formElement = formContainer.querySelector('form');\n\n if(!formElement) {\n return false;\n }\n\n const forms = window.epi.EPiServer.Forms;\n const currentForm = forms[formElement.id];\n\n if(!currentForm) {\n return false;\n }\n\n const elementsInfo = Object\n .keys(currentForm.ElementsInfo)\n .map(key => ({ key: key, ...currentForm.ElementsInfo[key]}));\n\n const sendLeadsFormFriendlyName = 'sendleadsform';\n const sendLeadsFormElementInfo = elementsInfo.find(x => x.friendlyName?.toLowerCase() === sendLeadsFormFriendlyName);\n\n if(!sendLeadsFormElementInfo) {\n return false;\n }\n\n const submittedData = formData.get(sendLeadsFormElementInfo.key);\n\n return submittedData?.toLocaleLowerCase() === 'true';\n};\n\n/**\n * @param {HTMLElement} formContainer The form container\n * @param {FormData} formData The sent form data\n */\nexport const handleBookShowingLead = (formContainer, formData) => {\n if(!checkIfBookShowingFormSentLead(formContainer, formData)) {\n return;\n }\n\n const formType = 'lead';\n const formLeadType = formContainer.dataset.formExtraLeadType;\n\n const properties = {\n officeId: configuration.office?.id,\n officeName: configuration.office?.name,\n brokerId: configuration.broker?.id,\n brokerName: configuration.broker?.name,\n estateId: configuration.estate?.id,\n estateShortId: configuration.estate?.shortId,\n culture: configuration.culture,\n leadType: formLeadType\n };\n\n TagManager.trackEvent(`${formType}-form`, properties);\n};\n","/* global $$epiforms */\n//import { WidgetInstance } from 'friendly-challenge';\nimport configuration from '../../configuration.mjs';\nimport { verifyPropertyExists } from '../../utils/verify-property-exists.mjs';\n\nconst widgets = [];\n\nexport default async() => {\n if(!verifyPropertyExists(window, 'epi', 'EPiServer', 'Forms')) {\n return;\n }\n\n if(typeof $$epiforms !== 'function') {\n console.warn('Could not find $$epiforms function. Friendly Captcha will not be initialized.');\n return;\n }\n\n $$epiforms.extend(true, window.epi.EPiServer.Forms, {\n Validators: {\n 'SkandiaMaklarna.Web.Core.Forms.Validators.FriendlyCaptchaElementValidator': function() {\n return { isValid: true };\n }\n }\n });\n\n let WidgetInstance = null;\n\n const friendlyCaptchaElements = [...document.querySelectorAll('div[data-friendly-captcha]')];\n for(const friendlyCaptchaElement of friendlyCaptchaElements) {\n const siteKey = configuration.friendlyCaptcha.siteKey;\n\n const targetElementId = friendlyCaptchaElement.dataset.friendlyCaptchaTargetElementId;\n const targetElement = document.getElementById(targetElementId);\n\n const formElement = friendlyCaptchaElement.closest('.EPiServerForms');\n if(!formElement) {\n console.warn('Could not find form element for friendly captcha element.', friendlyCaptchaElement);\n continue;\n }\n\n const submitButton = formElement.querySelector('button[data-f-type=\"submitbutton\"]');\n if(!!submitButton) {\n submitButton.disabled = true;\n } else {\n console.warn('Could not find submit button for friendly captcha element. If it exists it won\\'t be disabled.', friendlyCaptchaElement);\n }\n\n let puzzleEndpoint = 'https://api.friendlycaptcha.com/api/v1/puzzle';\n if(configuration.friendlyCaptcha.useEUEndpoint) {\n puzzleEndpoint = 'https://eu-api.friendlycaptcha.eu/api/v1/puzzle';\n }\n\n if(!WidgetInstance) {\n // Only load this if actually needed\n ({ WidgetInstance } = await import('friendly-challenge'));\n }\n\n const widget = new WidgetInstance(friendlyCaptchaElement, {\n sitekey: siteKey,\n language: configuration.culture,\n puzzleEndpoint: puzzleEndpoint,\n solutionFieldName: '-', // Do not create a hidden input field\n skipStyleInjection: false,\n doneCallback: token => {\n if(!targetElement) {\n return;\n }\n\n targetElement.value = token;\n\n if(!!submitButton) {\n submitButton.disabled = false;\n }\n }\n });\n\n $$epiforms(formElement).on('formsSubmitted', e => {\n if(e.isSuccess) {\n return;\n }\n\n if(!!submitButton) {\n // This needs a short delay since this happens before the form itself\n // tries to re-enable the submit button.\n window.setTimeout(() => {\n submitButton.disabled = true;\n }, 100);\n }\n\n console.info('Form submit failed. Resetting Friendly Captcha widget.');\n widget.reset();\n widget.start();\n });\n\n widgets.push({ widget, formElement });\n }\n};\n\nexport const destroy = () => {\n for(const { widget, formElement } of [...widgets]) {\n widget.destroy();\n widgets.splice(widgets.indexOf(widget), 1);\n\n $$epiforms(formElement).off('formsSubmitted');\n }\n};\n","export class VimeoVideo {\n #vimeoId = null;\n\n constructor(vimeoId) {\n if(!vimeoId) {\n throw new Error('vimeoId is required');\n }\n\n const parseResult = parseInt(vimeoId, 10);\n if(isNaN(parseResult)) {\n throw new Error(`Failed to parse vimeoId: ${vimeoId}`);\n }\n\n this.#vimeoId = vimeoId;\n }\n\n static tryParse(vimeoIdOrUrl) {\n // Matches for strings that contain:\n // * \"vimeo.com\"\n // * A segment that starts with \"/\", then has 5+ digits, then possibly ends with a \"?\"\n // * (Optional) Anything between those two segments\n const match = /vimeo\\.com.*?\\/(?\\d{5,})/.exec(vimeoIdOrUrl);\n\n if(!!match) {\n return new VimeoVideo(match.groups.vimeoId);\n }\n\n return null;\n }\n\n generateEmbedUrl(autoplay = false) {\n return `https://player.vimeo.com/video/${this.#vimeoId}?autoplay=${autoplay ? 1 : 0}&dnt=1`;\n }\n\n get watchUrl() {\n return `https://vimeo.com/${this.#vimeoId}`;\n }\n\n async getEmbedData() {\n const response = await fetch(`https://vimeo.com/api/oembed.json?url=${encodeURIComponent(this.watchUrl)}`);\n if(!response.ok) {\n throw new Error(`Failed to fetch embed data for ${this.watchUrl}`);\n }\n\n return await response.json();\n }\n\n async getThumbnailUrl() {\n const data = await this.getEmbedData();\n return data.thumbnail_url;\n }\n}\n","const cachePrefix = 'local-cache-';\n\nconst pruneCache = () => {\n const now = Date.now();\n Object.keys(localStorage)\n .filter(key => key.startsWith(cachePrefix))\n .forEach(key => {\n try {\n const { expiresAt } = JSON.parse(localStorage.getItem(key));\n if(expiresAt < now) {\n localStorage.removeItem(key);\n }\n } catch(e) {\n console.info('Failed to parse cache item', key, e);\n localStorage.removeItem(key);\n }\n });\n};\n\nconst readFromCache = (/** @type {string} */ key) => {\n pruneCache();\n\n const { data } = JSON.parse(localStorage.getItem(cachePrefix + key)) || { data : null };\n\n return data;\n};\n\nconst writeToCache = (/** @type {string} */ key, data, expireInMinutes = 1440) =>\n localStorage.setItem(cachePrefix + key, JSON.stringify({ expiresAt: Date.now() + (expireInMinutes * 60 * 1000), data }));\n\nexport { pruneCache, readFromCache, writeToCache };\n","import { VimeoVideo } from './vimeo-video.mjs';\nimport { readFromCache, writeToCache } from './local-cache.mjs';\n\nconst getThumbnailUrl = async vimeoIdOrUrl => {\n const vimeoVideo = VimeoVideo.tryParse(vimeoIdOrUrl);\n if(!vimeoVideo) {\n return null;\n }\n\n const cacheKey = `vimeo-thumbnail-${vimeoVideo.watchUrl}`;\n const cachedThumbnailUrl = readFromCache(cacheKey);\n if(!!cachedThumbnailUrl) {\n return cachedThumbnailUrl;\n }\n\n const thumbnailUrl = await vimeoVideo.getThumbnailUrl();\n writeToCache(cacheKey, thumbnailUrl);\n\n return thumbnailUrl;\n};\n\nexport { getThumbnailUrl };\n","import { getThumbnailUrl } from '../utils/vimeo-thumbnail-cache.mjs';\nimport { VimeoVideo } from '../utils/vimeo-video.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default (rootElement = document.body) => {\n const blocks = rootElement.querySelectorAll('.guide-step-block');\n for(const block of blocks) {\n setupBlock(block);\n }\n};\n\nconst setupBlock = block => {\n const videoSection = block.querySelector('.step-video');\n\n const { videoSrc } = videoSection.dataset;\n if(!!videoSrc) {\n insertThumbnailImage(videoSection, videoSrc);\n }\n\n setupEventHandlers(block);\n};\n\nconst insertThumbnailImage = async(container, videoSrc) => {\n const thumbnailUrl = await getThumbnailUrl(videoSrc);\n if(!thumbnailUrl) {\n container.remove();\n }\n\n const img = document.createElement('img');\n img.src = thumbnailUrl;\n img.classList.add('thumbnail');\n img.setAttribute('alt', '');\n img.setAttribute('role', 'presentation');\n\n const playButton = container.querySelector('.play-button');\n playButton.appendChild(img);\n};\n\nconst setupEventHandlers = (block) => {\n const playButton = block.querySelector('.play-button');\n playButton.addEventListener('click', () => {\n const videoSection = block.querySelector('.step-video');\n const { videoSrc } = videoSection.dataset;\n if(!videoSrc) {\n return;\n }\n\n createPlayer(block, true);\n });\n\n const closeButton = block.querySelector('.close-button');\n closeButton.addEventListener('click', () => {\n closeOverlay(block);\n destroyPlayer(block);\n });\n};\n\nconst createPlayer = (block, autoplay) => {\n const videoSection = block.querySelector('.step-video');\n const { videoSrc } = videoSection.dataset;\n\n const vimeoVideo = VimeoVideo.tryParse(videoSrc);\n if(!vimeoVideo) {\n return;\n }\n\n hideStaticElements(block);\n openOverlay(block);\n\n const iframeContainer = videoSection.querySelector('.iframe-container');\n\n const loader = document.createElement('div');\n loader.classList.add('loader');\n iframeContainer.appendChild(loader);\n\n const iframe = document.createElement('iframe');\n iframe.setAttribute('allow', 'fullscreen; autoplay;');\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('src', vimeoVideo.generateEmbedUrl(autoplay));\n\n iframeContainer.appendChild(iframe);\n\n const messageCallback = message => {\n if(message.source !== iframe.contentWindow) {\n return;\n }\n\n const data = JSON.parse(message.data);\n if(data.event !== 'ready' && data.event !== 'ping') {\n return;\n }\n\n loader.remove();\n window.removeEventListener('message', messageCallback);\n };\n\n window.addEventListener('message', messageCallback);\n iframe.contentWindow.postMessage({ method: 'ping' }, '*');\n};\n\nconst destroyPlayer = block => {\n const videoSection = block.querySelector('.step-video');\n const iframeContainer = videoSection.querySelector('.iframe-container');\n\n const iframe = iframeContainer.querySelector('iframe');\n iframe.remove();\n\n showStaticElements(block);\n};\n\nconst hideStaticElements = block => {\n const playButton = block.querySelector('.play-button');\n playButton.classList.add('hidden');\n\n const thumbnail = block.querySelector('.step-video img');\n thumbnail.classList.add('hidden');\n};\n\nconst showStaticElements = block => {\n const playButton = block.querySelector('.play-button');\n playButton.classList.remove('hidden');\n\n const thumbnail = block.querySelector('.step-video img');\n thumbnail.classList.remove('hidden');\n};\n\nconst openOverlay = block => {\n const videoContainer = block.querySelector('.video-container');\n videoContainer.classList.add('open');\n};\n\nconst closeOverlay = block => {\n const videoContainer = block.querySelector('.video-container');\n videoContainer.classList.remove('open');\n};\n","import initFormBlockBase from './form-blocks.mjs';\nimport initFriendlyCaptcha from './forms/friendly-captcha.mjs';\nimport initGuideBlocks from './guide-block.mjs';\n\n/**\n * Init all block scripts\n */\nexport default function() {\n initFormBlockBase();\n initFriendlyCaptcha();\n initGuideBlocks();\n}\n","/*! (c) Andrea Giammarchi - ISC */\nvar self = {};\ntry {\n self.EventTarget = (new EventTarget).constructor;\n} catch(EventTarget) {\n (function (Object, wm) {\n var create = Object.create;\n var defineProperty = Object.defineProperty;\n var proto = EventTarget.prototype;\n define(proto, 'addEventListener', function (type, listener, options) {\n for (var\n secret = wm.get(this),\n listeners = secret[type] || (secret[type] = []),\n i = 0, length = listeners.length; i < length; i++\n ) {\n if (listeners[i].listener === listener)\n return;\n }\n listeners.push({target: this, listener: listener, options: options});\n });\n define(proto, 'dispatchEvent', function (event) {\n var secret = wm.get(this);\n var listeners = secret[event.type];\n if (listeners) {\n define(event, 'target', this);\n define(event, 'currentTarget', this);\n listeners.slice(0).some(dispatch, event);\n delete event.currentTarget;\n delete event.target;\n }\n return true;\n });\n define(proto, 'removeEventListener', function (type, listener) {\n for (var\n secret = wm.get(this),\n /* istanbul ignore next */\n listeners = secret[type] || (secret[type] = []),\n i = 0, length = listeners.length; i < length; i++\n ) {\n if (listeners[i].listener === listener) {\n listeners.splice(i, 1);\n return;\n }\n }\n });\n self.EventTarget = EventTarget;\n function EventTarget() {'use strict';\n wm.set(this, create(null));\n }\n function define(target, name, value) {\n defineProperty(\n target,\n name,\n {\n configurable: true,\n writable: true,\n value: value\n }\n );\n }\n function dispatch(info) {\n var options = info.options;\n if (options && options.once)\n info.target.removeEventListener(this.type, info.listener);\n if (typeof info.listener === 'function')\n info.listener.call(info.target, this);\n else\n info.listener.handleEvent(this);\n return this._stopImmediatePropagationFlag;\n }\n }(Object, new WeakMap));\n}\nexport default self.EventTarget;\n","// Polyfill needeed for Safari 13...\r\nimport EventTarget from '@ungap/event-target';\r\n\r\nexport default class ScrollManager extends EventTarget {\r\n #scrolledElement = null;\r\n #measuredElement = null;\r\n #lastScrollPosition = 0;\r\n #lastSwitchPosition = 0;\r\n #scrollDirection = 'none';\r\n #boundOnScroll = null;\r\n\r\n constructor(scrolledElement, measuredElement) {\r\n super();\r\n\r\n if(!scrolledElement || !measuredElement) {\r\n throw new Error('scrolledElement and measuredElement is required.');\r\n }\r\n\r\n this.#boundOnScroll = this.#onScroll.bind(this);\r\n\r\n this.#scrolledElement = scrolledElement;\r\n this.#scrolledElement.addEventListener('scroll', this.#boundOnScroll, { passive: true });\r\n this.#measuredElement = measuredElement;\r\n }\r\n\r\n #onScroll() {\r\n const scrollTop = this.#measuredElement.scrollTop;\r\n this.#recordScrollPosition(scrollTop);\r\n }\r\n\r\n #recordScrollPosition(scrollPosition) {\r\n const lastPosition = this.#lastScrollPosition;\r\n const lastScrollDirection = this.#scrollDirection;\r\n\r\n let scrollDirection = 'none';\r\n if(scrollPosition > lastPosition) {\r\n scrollDirection = 'down';\r\n } else if(scrollPosition < lastPosition) {\r\n scrollDirection = 'up';\r\n }\r\n\r\n if(scrollDirection !== lastScrollDirection) {\r\n this.#lastSwitchPosition = lastPosition;\r\n }\r\n\r\n this.#scrollDirection = scrollDirection;\r\n this.#lastScrollPosition = scrollPosition;\r\n\r\n const event = new CustomEvent('scroll', { detail: {\r\n scrollPosition,\r\n scrollDirection: this.scrollDirection,\r\n scrolledDistance: this.scrolledDistance\r\n }});\r\n\r\n this.dispatchEvent(event);\r\n }\r\n\r\n get scrollDirection() {\r\n return this.#scrollDirection;\r\n }\r\n\r\n /**\r\n * @returns {number} The number of pixels scrolled in the current direction.\r\n */\r\n get scrolledDistance() {\r\n return Math.abs(this.#lastScrollPosition - this.#lastSwitchPosition);\r\n }\r\n\r\n destroy() {\r\n this.#scrolledElement.removeEventListener('scroll', this.#boundOnScroll);\r\n }\r\n}\r\n","/**\n * @callback HTMLElementCallback\n * @param {Element} element\n * @returns {boolean}\n */\n\n/**\n * @param {Element} element\n * @param {HTMLElementCallback} predicate\n * @param {boolean} includeSelf Include the starting element in the search\n * @returns {Element|null} The first ancestor that matches the predicate, or null if no match was found\n */\nexport let firstAnscestorOrDefault = (element, predicate, includeSelf = false) => {\n let parent = includeSelf ? element : element.parentElement;\n\n while(parent) {\n if(predicate(parent)) {\n return parent;\n }\n\n parent = parent.parentElement;\n }\n\n return null;\n};\n","import ScrollManager from '../utils/scroll-manager.mjs';\nimport { firstAnscestorOrDefault } from '../utils/dom-utils.mjs';\n\n/**\n * @type {IntersectionObserver}\n */\nlet intersectionObserver = null;\n\n/**\n * @type {ScrollManager}\n */\nlet scrollManager = null;\n\nexport default (\n rootElement = document.body,\n scrolledElement = document,\n measuredElement = document.documentElement) => {\n const containerElements = rootElement.querySelectorAll('.anchor-container');\n\n if(containerElements.length === 0) {\n return;\n }\n\n if(containerElements.length > 1) {\n throw new Error('Multiple anchor containers found, this is not supported.');\n }\n\n if(!!intersectionObserver || !!scrollManager) {\n destroy();\n }\n\n const containerElement = containerElements[0];\n initAnchorContainer(containerElement, scrolledElement, measuredElement);\n};\n\nexport let destroy = () => {\n if(intersectionObserver) {\n intersectionObserver.disconnect();\n intersectionObserver = null;\n }\n\n if(scrollManager) {\n scrollManager.destroy();\n scrollManager = null;\n }\n};\n\nconst initAnchorContainer = (containerElement, scrolledElement, measuredElement) => {\n const anchorList = containerElement.querySelector('.anchor-list');\n if(!anchorList) {\n console.warn('Anchor container is missing anchor list.', containerElement);\n return;\n }\n\n anchorList.childNodes.forEach(anchorItem => anchorItem.remove());\n\n const anchorItems = [...containerElement.querySelectorAll('[data-anchor-target]')];\n if(anchorItems.length === 0) {\n console.info('Anchor container is missing anchor items.', containerElement);\n return;\n }\n\n const anchorLinks = anchorItems\n .filter(anchorItem => {\n if(!anchorItem.id) {\n return false;\n }\n\n const anchorText = anchorItem.dataset.anchorTarget || anchorItem.textContent;\n if(!anchorText) {\n return false;\n }\n\n return true;\n })\n .map(anchorItem => {\n const anchorLink = document.createElement('a');\n anchorLink.href = '#' + anchorItem.id;\n anchorLink.textContent = anchorItem.dataset.anchorTarget || anchorItem.textContent;\n\n return { anchorItem, anchorLink };\n })\n .map(({ anchorItem, anchorLink }) => {\n const anchorListItem = document.createElement('li');\n anchorListItem.id = anchorItem.id + '-anchor-link';\n anchorListItem.appendChild(anchorLink);\n\n return anchorListItem;\n });\n\n const list = document.createElement('ol');\n anchorLinks.forEach(anchorLink => list.appendChild(anchorLink));\n anchorList.appendChild(list);\n\n makeSticky(scrolledElement, measuredElement, anchorList);\n initIntersectionObserver(containerElement, anchorItems);\n};\n\nconst makeSticky = (scrolledElement, measuredElement, stickyElement) => {\n scrollManager = new ScrollManager(scrolledElement, measuredElement);\n\n // 2024-08-26 KJ We are calculating the position of when to \"get sticky\", so if\n // the element is already sticky we need to return it to its original position\n // before we make the calculation.\n // This will trigger scroll events on the page though which isn't ideal but will\n // have to do for now.\n\n const alreadySticky = window.getComputedStyle(stickyElement).position === 'fixed';\n if(alreadySticky) {\n stickyElement.style.position = 'static';\n }\n\n const breakpoint = stickyElement.getBoundingClientRect().top + measuredElement.scrollTop;\n\n if(alreadySticky) {\n stickyElement.style.position = null;\n }\n\n scrollManager.addEventListener('scroll', /** @param {CustomEvent} scrollEvent */ (scrollEvent) => {\n const {\n scrollPosition,\n scrollDirection,\n scrolledDistance\n } = scrollEvent.detail;\n\n if(scrollPosition > breakpoint) {\n stickyElement.classList.add('sticky');\n } else if(scrollPosition <= breakpoint) {\n stickyElement.classList.remove('sticky');\n }\n\n const showAfter = 70; // These needs to be synced with the main menu\n const hideAfter = 70;\n\n if(scrollDirection === 'up' && scrolledDistance > showAfter) {\n stickyElement.classList.add('offset-sticky-header');\n }\n\n if(scrollDirection === 'down' && scrolledDistance > hideAfter) {\n stickyElement.classList.remove('offset-sticky-header');\n }\n });\n};\n\nconst initIntersectionObserver = (containerElement, anchorItems) => {\n intersectionObserver = new IntersectionObserver(\n /** @param {IntersectionObserverEntry[]} entries */ (entries) => {\n entries.forEach(entry => {\n let anchorItem = entry.target;\n if(anchorItem.hasAttribute('data-anchor-target-container')) {\n anchorItem = anchorItem.querySelector('[data-anchor-target]');\n if(!anchorItem) {\n console.warn('Found anchor container without anchor target.', entry.target);\n return;\n }\n }\n\n const anchorLinkId = anchorItem.id + '-anchor-link';\n const anchorLink = containerElement.querySelector(`#${anchorLinkId}`);\n if(!anchorLink) {\n console.warn('Found anchor item without anchor link.', anchorItem);\n return;\n }\n\n if(entry.isIntersecting) {\n anchorLink.classList.add('current-anchor');\n } else {\n anchorLink.classList.remove('current-anchor');\n }\n\n updateAnchorListScrollPosition(anchorLink);\n });\n },\n {\n rootMargin: `-25% 0px -75% 0px`\n });\n\n for(const anchorItem of anchorItems) {\n const anchorContainer = firstAnscestorOrDefault(anchorItem, e => e.hasAttribute('data-anchor-target-container'));\n intersectionObserver.observe(anchorContainer ?? anchorItem);\n }\n};\n\nconst updateAnchorListScrollPosition = anchorLink => {\n const anchorList = firstAnscestorOrDefault(anchorLink, e => e.classList.contains('anchor-list'));\n if(!anchorList) {\n console.warn('Found anchor link outside of anchor list.', anchorLink);\n return;\n }\n\n const actualList = anchorList.querySelector('ol');\n if(!actualList) {\n console.warn('Anchor list is missing an actual list.', anchorList);\n return;\n }\n\n const currentAnchors = actualList.querySelectorAll('.current-anchor');\n if(currentAnchors.length === 0) {\n return;\n }\n\n const anchor = currentAnchors[0];\n const anchorOffsetLeft = anchor.offsetLeft - (anchor.clientWidth / 2);\n\n actualList.scrollTo?.({ left: anchorOffsetLeft, behavior: 'auto' });\n};\n","/**\n * Apply classes to trigger animations on elements.\n */\nexport default function applyAnimations() {\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if(prefersReducedMotion) {\n return;\n }\n\n setupEnterScreenAnimations();\n setupHeroAnimations();\n setupBrokerProfileAnimations();\n}\n\nconst setupEnterScreenAnimations = () => {\n const elementsToFadeUpOnEnterScreen = document.querySelectorAll([\n // General\n '.office-brokers-block .broker-item',\n '.content-with-image-block',\n '.estate-list-block .estate-search-result-item',\n '.selling-point-block',\n '.guide-step-block',\n // Estate details\n '.brokers-and-showings',\n '.estate-images li',\n '.floor-plan li',\n '.map-section iframe',\n '.broker-profiles-section li'\n ].join(', '));\n\n elementsToFadeUpOnEnterScreen.forEach((element) => {\n element.style.visibility = 'hidden';\n });\n\n triggerOnEnterScreen((element) => {\n element.style.visibility = 'visible';\n animate(element, 'fade-up');\n }, elementsToFadeUpOnEnterScreen);\n};\n\nconst setupHeroAnimations = () => {\n const hero = document.querySelector('.hero-container');\n if(hero === null) {\n return;\n }\n\n const heading = hero.querySelector('h1');\n const ingress = hero.querySelector('p');\n const interactionContainer = hero.querySelector('.interactions-container');\n\n animate(heading, 'clip-right', 100);\n animate(ingress, 'clip-right', 100);\n animate(interactionContainer, 'fade-up', 1000);\n};\n\nconst setupBrokerProfileAnimations = () => {\n const brokerPageProfile = document.querySelector('.broker-page .broker-profile');\n if(brokerPageProfile === null) {\n return;\n }\n\n const brokerProfileHeading = brokerPageProfile.querySelector('h1');\n const brokerProfileInfo =\n brokerPageProfile.querySelectorAll('.profile-info :not(h1), .broker-profile-cta-container');\n\n animate(brokerProfileHeading, 'clip-right', 100);\n brokerProfileInfo.forEach((element, index) => {\n animate(element, 'fade-up', 600 + (index * 100));\n });\n};\n\n/**\n * @param {Element} element Element to animate\n * @param {string} animation Name of animation class to apply\n * @param {number} delay Delay in milliseconds before applying animation\n */\nconst animate = (element, animation, delay = 0) => {\n if(element === null) {\n return;\n }\n\n if(delay === 0) {\n element.classList.add(animation);\n return;\n }\n\n element.style.visibility = 'hidden';\n setTimeout(() => {\n element.style.visibility = 'visible';\n element.classList.add(animation);\n }, delay);\n};\n\n/**\n * @param {Function} enterScreenCallback Function to call when element enters screen\n * @param {Element[]} elements Elements to observe\n */\nconst triggerOnEnterScreen = (enterScreenCallback, elements) => {\n const enterScreenObserver = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if(entry.isIntersecting) {\n const element = entry.target;\n enterScreenCallback(element);\n enterScreenObserver.unobserve(element);\n }\n });\n });\n\n elements.forEach((element) => {\n enterScreenObserver.observe(element);\n });\n};\n","/**\n * @param {Element} rootElement\n */\nexport default function apply(rootElement = document.body) {\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if(prefersReducedMotion) {\n return;\n }\n\n const videos = [...rootElement.querySelectorAll('video[data-autoplay-if-allowed]')];\n for(const video of videos) {\n video.autoplay = true;\n }\n}\n","import { firstAnscestorOrDefault } from '../utils/dom-utils.mjs';\n\nconst ME_SECONDARY_BUTTON = 2;\n\n/**\n * @param {Element} rootElement\n */\nexport default function apply(rootElement = document.body) {\n const handleClick = (/** @type {MouseEvent} */ event) => {\n if(event.button === ME_SECONDARY_BUTTON) {\n // Ignore right clicks\n return;\n }\n\n /**\n * @type {HTMLElement}\n */\n // @ts-ignore\n const clickedElement = event.target;\n\n const clickTargetAncestor = firstAnscestorOrDefault(clickedElement, element => element.matches('[data-click-target]'));\n if(!clickedElement.matches('[data-click-target]') && !clickTargetAncestor) {\n // No click target found\n return;\n }\n\n const clickIgnoreAncestor = firstAnscestorOrDefault(clickedElement, element => element.matches('[data-click-ignore]'));\n if(clickedElement.matches('[data-click-ignore]') || !!clickIgnoreAncestor) {\n // Click should be ignored\n return;\n }\n\n const ownerElement = clickTargetAncestor ?? clickedElement;\n const clickTarget = ownerElement.getAttribute('data-click-target');\n if(!clickTarget) {\n return;\n }\n\n const targetElement = ownerElement.querySelector(clickTarget);\n if(!targetElement || targetElement === event.target) {\n return;\n }\n\n const newEvent = new window.MouseEvent('click', {\n view: event.view,\n bubbles: true,\n cancelable: true,\n button: event.button,\n buttons: event.buttons\n });\n\n targetElement.dispatchEvent(newEvent);\n\n event.preventDefault();\n event.stopPropagation();\n };\n\n rootElement.addEventListener('click', handleClick);\n rootElement.addEventListener('mouseup', handleClick);\n}\n","const COOKIE_TRACTOR_SCROLL_LOCK_CLASS = 'cc-active';\n\nexport default () => {\n handleCookieTractorScrollLock();\n};\n\n/**\n * Removes the class that locks site scroll when cookie tractor is active\n */\nconst handleCookieTractorScrollLock = () => {\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if(mutation.attributeName === 'class' && mutation.target.classList.contains(COOKIE_TRACTOR_SCROLL_LOCK_CLASS)) {\n mutation.target.classList.remove(COOKIE_TRACTOR_SCROLL_LOCK_CLASS);\n }\n });\n });\n\n observer.observe(document.documentElement, { attributes: true });\n};\n","import TagManager from '../utils/google-tag-manager.mjs';\nimport configuration from '../configuration.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default function apply(rootElement = document.body) {\n rootElement.addEventListener('click', eventHandler);\n rootElement.addEventListener('copy', eventHandler);\n}\n\nexport let eventHandler = (/** @type {Event} */ event) => {\n const { target } = event;\n\n if(!isContactLink(target)) {\n return;\n }\n\n const contactType = target.getAttribute('data-contact-request-trigger') || 'unknown';\n\n const properties = {\n officeId: configuration.office?.id,\n officeName: configuration.office?.name,\n brokerId: configuration.broker?.id,\n brokerName: configuration.broker?.name,\n estateId: configuration.estate?.id,\n estateShortId: configuration.estate?.shortId,\n culture: configuration.culture,\n contactType: contactType,\n eventType: event.type\n };\n\n TagManager.trackEvent('contact-link-clicked', properties);\n};\n\nexport let isContactLink = (/** @type {HTMLElement} */ element) => {\n if(element.tagName !== 'A') {\n return false;\n }\n\n if(!element.hasAttribute('data-contact-request-trigger')) {\n return false;\n }\n\n const href = element.getAttribute('href');\n if(!href || (!href.startsWith('mailto:') && !href.startsWith('tel:'))) {\n return false;\n }\n\n return true;\n};\n\n","export default function escapeStringRegexp(string) {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError('Expected a string');\n\t}\n\n\t// Escape characters with special meaning either inside or outside character sets.\n\t// Use a simple backslash escape when it’s always valid, and a `\\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.\n\treturn string\n\t\t.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&')\n\t\t.replace(/-/g, '\\\\x2d');\n}\n","// Polyfill needeed for Safari 13...\nimport EventTarget from '@ungap/event-target';\nimport escapeStringRegexp from 'escape-string-regexp';\nimport { firstAnscestorOrDefault } from './dom-utils.mjs';\n\nconst SPACE_KEY = ' ';\n\nexport default class Combobox extends EventTarget {\n /**\n * @type {HTMLElement}\n */\n #comboboxElement;\n\n /**\n * @type {HTMLElement}\n */\n #listboxElement;\n\n #selectedIndex = -1;\n #isOpen = false;\n\n get comboboxElement() {\n return this.#comboboxElement;\n }\n\n get listboxElement() {\n return this.#listboxElement;\n }\n\n /**\n * @param {HTMLElement} comoboxElement\n * @param {HTMLElement} listboxElement\n */\n constructor(comoboxElement, listboxElement) {\n super();\n\n if(!(comoboxElement instanceof HTMLElement)) {\n throw new Error('comboboxElement must be an HTMLElement.');\n }\n\n if(!(listboxElement instanceof HTMLElement)) {\n throw new Error('listboxElement must be an HTMLElement.');\n }\n\n this.#comboboxElement = comoboxElement;\n this.#listboxElement = listboxElement;\n\n this.#comboboxElement.parentElement.classList.add('js-enhanced');\n\n this.#setupEventListeners();\n }\n\n get #visibleListboxItems() {\n return [...this.#listboxElement.querySelectorAll('[role=\"option\"]:not([aria-hidden=\"true\"])')];\n }\n\n get #listboxItems() {\n return [...this.#listboxElement.querySelectorAll('[role=\"option\"]')];\n }\n\n get #listboxGroups() {\n return [...this.#listboxElement.querySelectorAll('[role=\"group\"]')];\n }\n\n get #isMultiselect() {\n return this.#listboxElement.getAttribute('aria-multiselectable') === 'true';\n }\n\n get #isDisabled() {\n return this.#comboboxElement.getAttribute('aria-disabled') === 'true';\n }\n\n get #supportsFiltering() {\n const comboboxElement = this.#comboboxElement;\n return comboboxElement instanceof HTMLInputElement && comboboxElement.dataset.supportsFiltering === 'true';\n }\n\n #setupEventListeners() {\n const comboboxElement = this.#comboboxElement;\n const listboxElement = this.#listboxElement;\n\n comboboxElement.addEventListener('keydown', this.#handleKeyDown.bind(this));\n\n comboboxElement.addEventListener('focus', () => {\n this.#updateARIAAttributes();\n });\n\n comboboxElement.addEventListener('click', () => {\n this.open();\n this.#updateARIAAttributes();\n });\n\n comboboxElement.addEventListener('blur', e => {\n const newFocus = e.relatedTarget;\n if(listboxElement.contains(newFocus)) {\n this.#comboboxElement.focus();\n return;\n }\n\n // Delay this a tiny bit to not interfere with the click event\n window.setTimeout(() => {\n this.#reset();\n }, 250);\n });\n\n listboxElement.addEventListener('click', this.#handleOptionClick.bind(this));\n\n if(this.#supportsFiltering) {\n comboboxElement.addEventListener('input', this.#handleFilterInput.bind(this));\n }\n }\n\n open() {\n if(this.#isDisabled) {\n return;\n }\n\n this.#isOpen = true;\n\n this.#updateVisibilityAttributes();\n this.#updateScrollPosition();\n }\n\n close() {\n this.#isOpen = false;\n this.#selectedIndex = -1;\n\n if(this.#supportsFiltering) {\n this.#comboboxElement.value = '';\n this.#handleFilterInput({ target: this.#comboboxElement });\n }\n\n this.#updateARIAAttributes();\n this.#updateVisibilityAttributes();\n }\n\n #reset() {\n this.close();\n\n this.#updateARIAAttributes();\n this.#updateScrollPosition();\n }\n\n /**\n * @param {KeyboardEvent} event\n */\n #handleKeyDown(event) {\n if(this.#isDisabled) {\n return;\n }\n\n this.open();\n\n const suggestions = this.#visibleListboxItems;\n const currentlySelectedIndex = this.#selectedIndex;\n\n let newIndex = currentlySelectedIndex;\n switch (event.key) {\n case 'ArrowDown':\n newIndex++;\n break;\n case 'ArrowUp':\n newIndex--;\n break;\n case SPACE_KEY:\n if(this.#isOpen) {\n // Return here to not prevent the default action of the space key\n // when the combobox is is already open\n return;\n }\n\n this.open();\n this.#updateARIAAttributes();\n\n break;\n case 'Escape':\n this.#reset();\n return;\n case 'Enter':\n this.#handleEnterKey(event);\n return;\n case 'Tab':\n if(this.#isMultiselect) {\n this.close();\n return;\n }\n\n // If we tab backwards we should not select anything\n if(!event.shiftKey) {\n this.#handleEnterKey(event);\n }\n\n this.#reset();\n return;\n default:\n return;\n }\n\n event.preventDefault();\n\n if(newIndex > suggestions.length - 1) {\n newIndex = suggestions.length - 1;\n } else if(newIndex < 0) {\n newIndex = -1;\n }\n\n this.#selectedIndex = newIndex;\n\n this.#updateScrollPosition();\n this.#updateARIAAttributes();\n }\n\n /**\n * @param {InputEvent} event\n */\n #handleFilterInput(event) {\n const filterText = event.target.value.trim();\n const items = this.#listboxItems;\n\n const hasFilterText = filterText.length > 0;\n const filterRegex = new RegExp('^' + escapeStringRegexp(filterText), 'i');\n\n for(const item of items) {\n const text = item.textContent.trim();\n const matches = hasFilterText ? filterRegex.test(text) : true;\n\n item.setAttribute('aria-hidden', matches ? 'false' : 'true');\n }\n\n const itemGroups = this.#listboxGroups;\n for(const group of itemGroups) {\n const visibleItems = [...group.querySelectorAll('[role=\"option\"]:not([aria-hidden=\"true\"])')];\n group.setAttribute('aria-hidden', visibleItems.length === 0 ? 'true' : 'false');\n }\n\n }\n\n /**\n * @param {MouseEvent} event\n */\n #handleOptionClick(event) {\n if(this.#isDisabled) {\n return;\n }\n\n const target = firstAnscestorOrDefault(event.target, element => element.getAttribute('role') === 'option', true);\n if(!target) {\n return;\n }\n\n const items = this.#visibleListboxItems;\n const clickedItem = items.find(item => item.id === target.id);\n\n if(clickedItem.getAttribute('aria-disabled') === 'true') {\n return;\n }\n\n this.#handleItemSelectedEvent(clickedItem);\n\n if(!this.#isMultiselect) {\n this.#reset();\n }\n }\n\n #handleEnterKey(event) {\n const items = this.#visibleListboxItems;\n const selectedIndex = this.#selectedIndex;\n\n if(selectedIndex === -1) {\n return;\n }\n\n event.preventDefault();\n\n const selecteditem = items[selectedIndex];\n\n if(selecteditem.getAttribute('aria-disabled') === 'true') {\n return;\n }\n\n this.#handleItemSelectedEvent(selecteditem);\n\n this.#updateARIAAttributes();\n\n if(!this.#isMultiselect) {\n this.#reset();\n }\n }\n\n /**\n * @param {HTMLElement} itemElement\n */\n #handleItemSelectedEvent(itemElement) {\n let eventName = 'item-selected';\n if(this.#isMultiselect) {\n const isSelected = itemElement.getAttribute('aria-selected') === 'true';\n itemElement.setAttribute('aria-selected', isSelected ? 'false' : 'true');\n\n if(isSelected) {\n eventName = 'item-deselected';\n }\n }\n\n const event = new CustomEvent(eventName, {\n detail: {\n sender: this,\n element: itemElement\n }\n });\n\n this.dispatchEvent(event);\n }\n\n // 2023-09-04 KJ Code coverage disabled since scroll interactions aren't really testable using JSDOM\n // wihtout mocking essentially everyting.\n #updateScrollPosition() /* istanbul ignore next */ {\n const listboxElement = this.#listboxElement;\n\n const style = window.getComputedStyle(listboxElement);\n if(style.overflowY !== 'scroll') {\n return;\n }\n\n if(this.#selectedIndex === -1) {\n listboxElement.scrollTop = 0;\n return;\n }\n\n const items = this.#visibleListboxItems;\n const selectedItem = items[this.#selectedIndex];\n\n const scrollHeight = listboxElement.scrollHeight;\n const listboxHeight = listboxElement.clientHeight;\n\n if(scrollHeight < listboxHeight) {\n return;\n }\n\n const scrollTop = listboxElement.scrollTop;\n const itemTop = selectedItem.offsetTop;\n const itemBottom = itemTop + selectedItem.offsetHeight;\n const listboxBottom = listboxHeight + scrollTop;\n\n if(itemBottom > listboxBottom) {\n listboxElement.scrollTop = itemBottom - listboxHeight;\n } else if(itemTop < scrollTop) {\n listboxElement.scrollTop = itemTop;\n }\n }\n\n #updateARIAAttributes() {\n const comboboxElement = this.#comboboxElement;\n const items = this.#visibleListboxItems;\n\n this.#updateVisibilityAttributes();\n\n if(this.#selectedIndex === -1) {\n comboboxElement.removeAttribute('aria-activedescendant');\n } else {\n const selectedItem = items[this.#selectedIndex];\n comboboxElement.setAttribute('aria-activedescendant', selectedItem.id);\n }\n\n for(const [index, itemElement] of items.entries()) {\n if(!this.#isMultiselect) {\n itemElement.setAttribute('aria-selected', index === this.#selectedIndex ? 'true' : 'false');\n } else {\n itemElement.classList.toggle('multiselect-current', index === this.#selectedIndex);\n }\n }\n }\n\n #updateVisibilityAttributes() {\n const comboboxElement = this.#comboboxElement;\n const listboxElement = this.#listboxElement;\n const items = this.#visibleListboxItems;\n\n const showPanel = this.#isOpen && items.length > 0;\n\n comboboxElement.setAttribute('aria-expanded', showPanel > 0 ? 'true' : 'false');\n listboxElement.classList.toggle('open', showPanel);\n }\n}\n","import Combobox from '../utils/combobox.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default function apply(rootElement = document.body) {\n const elements = rootElement.querySelectorAll('.language-selector');\n\n for(const containerElement of elements) {\n const comboboxElement = containerElement.querySelector('.language-selector-combobox');\n const listboxElement = containerElement.querySelector('.language-selector-listbox');\n\n const combobox = new Combobox(comboboxElement, listboxElement);\n combobox.addEventListener('item-selected', event => {\n const { element } = event.detail;\n const url = element.dataset.url;\n\n if(!!url) {\n window.location.href = url;\n }\n });\n }\n}\n","/**\n * Resets the opacity of overlays to allow transitions to run.\n */\nexport default function apply() {\n\n // Overlays have an explicit style attribute to avoid transitions\n // during load.\n const overlayElements = document.querySelectorAll('.initialize-overlay');\n for(const overlayElement of overlayElements) {\n if(!!overlayElement['style']) {\n overlayElement['style'].opacity = null;\n }\n }\n}\n","/**\n * @param {Function} func The function to debounce\n * @param {number} timeout The timeout until the method is called in milliseconds\n * @returns {Function} The debounced function\n */\nexport let debounce = (func, timeout = 500) => {\n let timer;\n return (...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => { func.apply(this, args); }, timeout);\n };\n};\n","import { firstAnscestorOrDefault } from '../utils/dom-utils.mjs';\nimport { debounce } from '../utils/debounce.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default function apply(rootElement = document.body) {\n const calculateButtonVisibility = (button, content) => {\n const contentHeight = content.offsetHeight;\n const contentScrollHeight = content.scrollHeight;\n\n if(contentHeight < contentScrollHeight) {\n button.style.display = null;\n } else {\n button.style.display = 'none';\n }\n };\n\n const initAccordions = (accordions = [...rootElement.querySelectorAll('.read-more-accordion')]) => {\n accordions.forEach(accordion => {\n const button = accordion.querySelector('button');\n const content = accordion.querySelector('.content');\n\n if(!button || !content) {\n console.warn('Invalid markup for read more accordion. Could not find button or content element.', accordion);\n return;\n }\n\n calculateButtonVisibility(button, content);\n });\n };\n\n const initObserver = () => {\n const observer = new MutationObserver((mutations) => {\n mutations.forEach(mutation => {\n if(mutation.type === 'childList') {\n const elements = [...mutation.addedNodes]\n .filter(node => node.nodeType === Node.ELEMENT_NODE) // Filter out non-element nodes such as text nodes and comments\n .filter(element => !!firstAnscestorOrDefault(element, element => element.classList.contains('read-more-accordion')) || !!element.querySelector('.read-more-accordion'));\n\n const accordions = elements\n .flatMap(element => [\n firstAnscestorOrDefault(element, element => element.classList.contains('read-more-accordion')),\n ...element.querySelectorAll('.read-more-accordion')\n ])\n .filter(accordionElement => !!accordionElement);\n initAccordions(accordions);\n }\n });\n });\n\n observer.observe(rootElement, { subtree: true, childList: true });\n };\n\n const handleClick = event => {\n /**\n * @type {HTMLElement}\n */\n const clickedElement = event.target;\n\n if(clickedElement.nodeName !== 'BUTTON' && clickedElement.nodeName !== 'SPAN') {\n return;\n }\n\n const button = clickedElement.nodeName === 'BUTTON' ? clickedElement : clickedElement.parentElement;\n if(!button) {\n return;\n }\n\n const accordionContainer = firstAnscestorOrDefault(clickedElement, element => element.classList.contains('read-more-accordion'));\n if(!accordionContainer) {\n return;\n }\n\n const accordionContent = accordionContainer.querySelector('.content');\n if(!accordionContent) {\n console.warn('Invalid markup for read more accordion. Could not find content element.', accordionContainer);\n return;\n }\n\n const isExpanded = button.getAttribute('aria-expanded') === 'true';\n button.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');\n accordionContainer.classList.toggle('expanded', !isExpanded);\n\n event.preventDefault();\n event.stopPropagation();\n };\n\n rootElement.addEventListener('click', handleClick);\n\n setTimeout(() => {\n initAccordions();\n initObserver();\n }, 250);\n\n window.addEventListener('resize', debounce(() => {\n initAccordions();\n }, 100), true);\n}\n","import ScrollManager from '../utils/scroll-manager.mjs';\r\n\r\n/**\r\n * @param {Element|Document} scrolledElement Element that is scrolled\r\n * @param {Element} measuredElement Element that is measured for scroll position\r\n * @param {Element} stickyElement Element that is made sticky\r\n * @param {number} breakpoint Number of pixels from the top to scroll before the sticky menu is enabled\r\n * @param {number} showAfter Number of pixels to scroll upwards before the sticky menu is shown\r\n * @param {number} hideAfter Number of pixels to scroll downwards before the sticky menu is hidden\r\n */\r\nexport default function apply(\r\n scrolledElement = document,\r\n measuredElement = document.documentElement,\r\n stickyElement = document.getElementById('main-header'),\r\n breakpoint = 150,\r\n showAfter = 70,\r\n hideAfter = 70) {\r\n\r\n if(!scrolledElement || !measuredElement || !stickyElement) {\r\n console.error('scrolledElement, measuredElement and stickyElement are required.');\r\n return;\r\n }\r\n\r\n const manager = new ScrollManager(scrolledElement, measuredElement);\r\n\r\n manager.addEventListener('scroll', /** @param {CustomEvent} scrollEvent */ (scrollEvent) => {\r\n const {\r\n scrollPosition,\r\n scrollDirection,\r\n scrolledDistance\r\n } = scrollEvent.detail;\r\n\r\n if(scrollPosition > breakpoint) {\r\n stickyElement.classList.add('sticky');\r\n } else if(scrollPosition === 0) {\r\n stickyElement.classList.remove('sticky');\r\n }\r\n\r\n if(scrollDirection === 'up' && scrolledDistance > showAfter) {\r\n stickyElement.classList.add('show-sticky');\r\n }\r\n\r\n if(scrollDirection === 'down' && scrolledDistance > hideAfter) {\r\n stickyElement.classList.remove('show-sticky');\r\n }\r\n });\r\n}\r\n","// Polyfill needeed for Safari 13...\nimport EventTarget from '@ungap/event-target';\n\nclass Postbox extends EventTarget {\n}\n\nexport default new Postbox();\n","import { firstAnscestorOrDefault } from '../utils/dom-utils.mjs';\nimport postbox from '../postbox.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default function apply(rootElement = document.body) {\n const handleKeydown = (/** @type {KeyboardEvent} */ event) => {\n const targetElement = event.target;\n if(!isInTablist(targetElement)) {\n return;\n }\n\n const tablist = getTablist(targetElement);\n let handled = false;\n\n switch (event.key) {\n case 'ArrowLeft':\n selectPreviousTab(tablist);\n handled = true;\n break;\n case 'ArrowRight':\n selectNextTab(tablist);\n handled = true;\n break;\n case 'Home':\n selectTab(getFirstTab(tablist));\n handled = true;\n break;\n case 'End':\n selectTab(getLastTab(tablist));\n handled = true;\n break;\n default:\n break;\n }\n\n if(handled) {\n event.preventDefault();\n event.stopPropagation();\n }\n };\n\n const handleClick = (/** @type {MouseEvent} */ event) => {\n const targetElement = event.target;\n if(!isInTablist(targetElement)) {\n return;\n }\n\n const tab = firstAnscestorOrDefault(targetElement, element => element.matches('[role=\"tab\"]'), true);\n selectTab(tab);\n };\n\n rootElement.addEventListener('click', handleClick);\n rootElement.addEventListener('keydown', handleKeydown);\n}\n\nexport let getTablist = (/** @type {HTMLElement} */ element) => {\n return firstAnscestorOrDefault(element, element => element.matches('[role=\"tablist\"]'), true);\n};\n\nexport let isInTablist = (/** @type {HTMLElement} */ element) => {\n return !!getTablist(element);\n};\n\nexport let getCurrentTab = (/** @type {HTMLElement} */ tablist) => {\n return tablist.querySelector('[role=\"tab\"][aria-selected=\"true\"]');\n};\n\nexport let getCurrentTabPanel = (/** @type {HTMLElement} */ tablist) => {\n const currentTab = getCurrentTab(tablist);\n if(!currentTab) {\n return null;\n }\n\n const tabId = currentTab.getAttribute('aria-controls');\n return document.querySelector(`[role=\"tabpanel\"][id=\"${tabId}\"]`);\n};\n\nexport let getFirstTab = (/** @type {HTMLElement} */ tablist) => {\n return tablist.querySelector('[role=\"tab\"]');\n};\n\nexport let getLastTab = (/** @type {HTMLElement} */ tablist) => {\n const tabs = tablist.querySelectorAll('[role=\"tab\"]');\n return tabs[tabs.length - 1];\n};\n\nexport let getNextTab = (/** @type {HTMLElement} */ tab) => {\n let nextSibling;\n do {\n nextSibling = tab.nextElementSibling;\n } while(nextSibling && nextSibling.getAttribute('role') !== 'tab');\n\n return nextSibling;\n};\n\nexport let getPreviousTab = (/** @type {HTMLElement} */ tab) => {\n let previousSibling;\n do {\n previousSibling = tab.previousElementSibling;\n } while(previousSibling && previousSibling.getAttribute('role') !== 'tab');\n\n return previousSibling;\n};\n\nexport let selectTab = (/** @type {HTMLElement} */ tab, skipFocus = false) => {\n if(!tab) {\n return;\n }\n\n const tablist = getTablist(tab);\n\n const tabId = tab.getAttribute('aria-controls');\n const panel = document.querySelector(`[role=\"tabpanel\"][id=\"${tabId}\"]`);\n if(!panel) {\n return;\n }\n\n const currentTab = getCurrentTab(tablist);\n const currentPanel = getCurrentTabPanel(tablist); // This needs to be fetched before the current tab is deselected\n\n if(!!currentTab) {\n currentTab.setAttribute('aria-selected', 'false');\n currentTab.setAttribute('tabindex', '-1');\n }\n\n if(!!currentPanel) {\n currentPanel.setAttribute('aria-hidden', 'true');\n currentPanel.inert = true;\n }\n\n tab.setAttribute('aria-selected', 'true');\n tab.removeAttribute('tabindex');\n\n if(!skipFocus) {\n tab.focus();\n }\n\n panel.setAttribute('aria-hidden', 'false');\n panel.inert = false;\n\n postbox.dispatchEvent(new CustomEvent('tab-selected', { detail: { tablist, tab, panel } }));\n};\n\nconst selectPreviousTab = (/** @type {HTMLElement} */ tablist) => {\n const currentTab = getCurrentTab(tablist);\n if(!currentTab) {\n return;\n }\n\n let previousTab = getPreviousTab(currentTab);\n if(!previousTab) {\n previousTab = getLastTab(tablist);\n }\n\n selectTab(previousTab);\n};\n\nexport let selectNextTab = (/** @type {HTMLElement} */ tablist) => {\n const currentTab = getCurrentTab(tablist);\n if(!currentTab) {\n return;\n }\n\n let nextTab = getNextTab(currentTab);\n if(!nextTab) {\n nextTab = getFirstTab(tablist);\n }\n\n selectTab(nextTab);\n};\n","import { firstAnscestorOrDefault } from '../utils/dom-utils.mjs';\r\n\r\n/**\r\n * @param {Element} rootElement\r\n */\r\nexport default function apply(rootElement = document.documentElement) {\r\n /**\r\n * @param {HTMLElement} element\r\n * @returns {boolean} true if the element should be ignored, otherwise false\r\n */\r\n const isIgnoredElement = (element) => {\r\n let parent = element;\r\n do {\r\n const attributes = [...element.attributes];\r\n\r\n if(attributes.some(attribute => attribute.name === 'data-toggle-ignore')) {\r\n console.log('Ignored click for', parent);\r\n return true;\r\n }\r\n\r\n if(attributes.some(attribute => attribute.name === 'data-toggle-open')) {\r\n break;\r\n }\r\n\r\n parent = parent.parentElement;\r\n } while(!!parent);\r\n\r\n return false;\r\n };\r\n\r\n const getTargetElement = (attributes, toggledElement) => {\r\n let targetElement = toggledElement;\r\n const targetSelector = attributes.find(x => x.name === 'data-toggle-open')?.value;\r\n if(!!targetSelector) {\r\n if(targetSelector.startsWith('#')) {\r\n targetElement = rootElement.querySelector(targetSelector);\r\n } else {\r\n targetElement = toggledElement.querySelector(targetSelector);\r\n }\r\n\r\n if(!targetElement) {\r\n throw new Error(`Could not find target element with selector ${targetSelector}.`);\r\n }\r\n }\r\n\r\n return targetElement;\r\n };\r\n\r\n const getSynchronizedElements = targetElement => {\r\n let elements = [];\r\n\r\n const targetSelector = targetElement.getAttribute('data-toggle-open-synchronize');\r\n if(!!targetSelector) {\r\n elements = [...rootElement.querySelectorAll(targetSelector)];\r\n }\r\n\r\n return elements;\r\n };\r\n\r\n /**\r\n * @param {HTMLElement[]} targetElements\r\n * @param {boolean} setOpenClass\r\n * @param {string} targetClassName\r\n */\r\n const toggleElementClassesOnTargets = (targetElements, setOpenClass, targetClassName) => {\r\n for(const targetElement of targetElements) {\r\n targetElement.classList.toggle(targetClassName, setOpenClass);\r\n\r\n if(targetElement.getAttributeNames().some(x => x === 'aria-hidden')) {\r\n targetElement.setAttribute('aria-hidden', setOpenClass ? 'false' : 'true');\r\n }\r\n }\r\n };\r\n\r\n /**\r\n * @param {HTMLElement[]} sourceElements\r\n * @param {boolean} setOpenClass\r\n */\r\n const toggleElementClassesOnSources = (sourceElements, setOpenClass) => {\r\n for(const sourceElement of sourceElements) {\r\n if(sourceElement.getAttributeNames().some(x => x === 'aria-expanded')) {\r\n sourceElement.setAttribute('aria-expanded', setOpenClass ? 'true' : 'false');\r\n }\r\n }\r\n };\r\n\r\n const handleClick = event => {\r\n /**\r\n * @type {HTMLElement}\r\n */\r\n const clickedElement = event.target;\r\n\r\n if(isIgnoredElement(clickedElement)) {\r\n return;\r\n }\r\n\r\n let toggledElement = null;\r\n\r\n const clickedElementAttributes = [...clickedElement.attributes].map(attribute => attribute.name);\r\n if(clickedElementAttributes.includes('data-toggle-open')) {\r\n toggledElement = clickedElement;\r\n } else {\r\n toggledElement = firstAnscestorOrDefault(clickedElement, element => {\r\n const attributes = [...element.attributes].map(attribute => attribute.name);\r\n\r\n return attributes.includes('data-toggle-open');\r\n });\r\n }\r\n\r\n if(toggledElement === null) {\r\n return;\r\n }\r\n\r\n const attributes = [...toggledElement.attributes];\r\n const attributeNames = attributes.map(attribute => attribute.name);\r\n\r\n const targetElement = getTargetElement(attributes, toggledElement);\r\n\r\n const targetClassName = attributes.find(x => x.name === 'data-toggle-open-class-name')?.value ?? 'open';\r\n\r\n let setOpenClass = !targetElement.classList.contains(targetClassName);\r\n if(attributeNames.includes('data-toggle-open-force')) {\r\n setOpenClass = true;\r\n }\r\n\r\n const elementsToSynchronize = getSynchronizedElements(targetElement);\r\n\r\n toggleElementClassesOnTargets([targetElement, ...elementsToSynchronize], setOpenClass, targetClassName);\r\n\r\n const sourceElements = [clickedElement, ...document.querySelectorAll(`[data-toggle-open=\"${toggledElement.getAttribute('data-toggle-open')}\"]`)];\r\n\r\n toggleElementClassesOnSources(sourceElements, setOpenClass);\r\n\r\n if(attributeNames.includes('data-toggle-open-navigate')) {\r\n // If we also want navigation to occur (like going to an anchor)\r\n // we need to exit early here to allow the event to propagate.\r\n return;\r\n }\r\n\r\n const focusId = attributes.find(x => x.name === 'data-toggle-open-focus-id')?.value;\r\n if(!!focusId) {\r\n const focusElement = document.getElementById(focusId);\r\n if(!!focusElement) {\r\n setTimeout(() => focusElement.focus(), 0);\r\n }\r\n }\r\n\r\n const scrollToId = attributes.find(x => x.name === 'data-toggle-open-scroll-to-id')?.value;\r\n if(!!scrollToId) {\r\n setTimeout(() => {\r\n window.location.hash = '';\r\n window.location.hash = scrollToId;\r\n }, 0);\r\n }\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n };\r\n\r\n rootElement.addEventListener('click', handleClick);\r\n}\r\n","import applyAnchorContainer from './anchor-container.mjs';\nimport applyAnimations from './animate.mjs';\nimport applyAutoPlayVideo from './autoplay-video.mjs';\nimport applyClickableContainers from './clickable-containers.mjs';\nimport applyCookieTractor from './cookie-tractor.mjs';\nimport applyGoogleTagManagerEvents from './google-tag-manager-events.mjs';\nimport applyLanguageSelectors from './language-selector.mjs';\nimport applyOverlayScripts from './overlays.mjs';\nimport applyReadMoreAccordion from './read-more-accordion.mjs';\nimport applyStickyHeader from './sticky-header.mjs';\nimport applyTabs from './tabs.mjs';\nimport applyToggleOpen from './toggle-open.mjs';\n\n/**\n * Init all page scripts\n */\nexport default function() {\n applyAnchorContainer();\n applyAnimations();\n applyAutoPlayVideo();\n applyClickableContainers();\n applyCookieTractor();\n applyGoogleTagManagerEvents();\n applyLanguageSelectors();\n applyOverlayScripts();\n applyReadMoreAccordion();\n applyStickyHeader();\n applyTabs();\n applyToggleOpen();\n}\n","import configuration from '../configuration.mjs';\n\nexport let getPageLanguage = (fallback = 'sv') => {\n return configuration.culture ?? fallback;\n};\n","import initializeAnchorContainer, { destroy as destroyAnchorContainer } from '../page-scripts/anchor-container.mjs';\nimport { debounce } from '../utils/debounce.mjs';\nimport { getPageLanguage } from '../utils/get-page-language.mjs';\n\nconst SEARCH_DEBOUNCE_TIMEOUT = 50;\nconst LOADER_TIMEOUT = 200;\n\n/**\n * @param {Element} rootElement\n */\nexport default (rootElement = document.body) => {\n const pageElement = rootElement?.querySelector('#broker-search-page');\n\n if(!pageElement) {\n return;\n }\n\n initSearchForm(pageElement);\n};\n\nconst initSearchForm = pageElement => {\n const searchForm = pageElement.querySelector('form');\n const searchInput = searchForm.querySelector('#query');\n const resetLink = searchForm.querySelector('.reset-link');\n const regionContainer = pageElement.querySelector('.region-group .filters');\n\n searchForm.addEventListener('keypress', event => {\n // Prevent form submission on enter in the search input\n if(event.key === 'Enter' && event.target === searchInput) {\n event.stopPropagation();\n event.preventDefault();\n return;\n }\n });\n\n const getSelectedRegion = () => {\n const selectedRadioButton = pageElement.querySelector('input[name=\\'region\\']:checked');\n return selectedRadioButton?.value;\n };\n\n searchInput.addEventListener('keyup', () => {\n const searchTerm = searchInput.value;\n const region = getSelectedRegion();\n debouncedPerformSearch(pageElement, searchTerm, region);\n });\n\n regionContainer?.addEventListener('click', e => {\n if(e.target.tagName !== 'INPUT') {\n return;\n }\n\n const searchTerm = searchInput.value;\n const region = getSelectedRegion();\n performSearch(pageElement, searchTerm, region);\n });\n\n resetLink.addEventListener('click', event => {\n event.stopPropagation();\n event.preventDefault();\n\n searchInput.value = '';\n\n const regionFilters = pageElement.querySelectorAll('input[name=\\'region\\']');\n regionFilters[0].checked = true;\n\n performSearch(pageElement);\n });\n};\n\nconst performSearch = async(pageElement, searchTerm = '', region = '') => {\n let doneLoading = false;\n\n // Only show loader if the search is taking some\n // time so we avoid flickering\n window.setTimeout(() => {\n if(!doneLoading) {\n insertLoader(pageElement);\n }\n }, LOADER_TIMEOUT);\n\n updateUrl(searchTerm, region);\n\n const html = await fetchResults(searchTerm, region);\n\n doneLoading = true;\n\n if(html === undefined) {\n // Request was aborted, just return and wait for the next one\n return;\n }\n\n if(html === null) {\n // TODO Make this localizable when get have a service for that\n insertErrorMessage(pageElement, 'An error occured while searching.');\n return;\n }\n\n destroyAnchorContainer();\n\n const resultsContainer = pageElement.querySelector('.results');\n resultsContainer.innerHTML = html;\n\n if(searchTerm.length === 0 && region.length === 0) {\n initializeAnchorContainer();\n }\n};\n\nconst updateUrl = (searchTerm, region) => {\n const url = new URL(window.location);\n if(searchTerm.length !== 0) {\n url.searchParams.set('query', searchTerm);\n } else {\n url.searchParams.delete('query');\n }\n if(region.length !== 0) {\n url.searchParams.set('region', region);\n } else {\n url.searchParams.delete('region');\n }\n\n window.history.replaceState({}, '', url);\n};\n\nconst insertLoader = pageElement => {\n const resultsContainer = pageElement.querySelector('.results');\n resultsContainer.innerHTML = '';\n};\n\nconst insertErrorMessage = (pageElement, message) => {\n const resultsContainer = pageElement.querySelector('.results');\n resultsContainer.innerHTML = '';\n\n const errorMessage = document.createElement('div');\n errorMessage.classList.add('error-message');\n errorMessage.textContent = message;\n\n resultsContainer.appendChild(errorMessage);\n};\n\nconst debouncedPerformSearch = debounce(performSearch, SEARCH_DEBOUNCE_TIMEOUT);\n\n/**\n * @type {AbortController}\n */\nlet abortController = null;\n\nconst fetchResults = async(searchTerm = '', region = '') => {\n if(abortController !== null) {\n abortController.abort();\n }\n\n abortController = new AbortController();\n const signal = abortController.signal;\n\n const culture = getPageLanguage();\n const url = `/api/${culture}/broker-search/html?query=${encodeURIComponent(searchTerm)}®ion=${encodeURIComponent(region)}`;\n\n let response;\n try {\n response = await fetch(url, { signal });\n } catch(error) {\n if(error.name === 'AbortError') {\n return;\n }\n\n throw error;\n }\n\n if(!response.ok) {\n console.error(`Failed to fetch search results: ${response.status} ${response.statusText}`);\n return null;\n }\n\n return await response.text();\n};\n","import postbox from '../../postbox.mjs';\nimport configuration from '../../configuration.mjs';\nimport { getPageLanguage } from '../../utils/get-page-language.mjs';\n\nconst BiddingRefreshIntervalInMilliseconds = 5_000;\n\nlet updateHandle = null;\nlet loading = false;\n\nconst updateBiddingInformation = async() => {\n if(loading) {\n return;\n }\n\n loading = true;\n\n try {\n const pageLanguage = getPageLanguage();\n const estateId = configuration.estate.shortId;\n const response = await fetch(`/api/${pageLanguage}/estate/${estateId}/bidding`);\n\n if(!response.ok) {\n return;\n }\n\n const biddingHtml = await response.text();\n\n const biddingDialogContent = document.querySelector('#bidding-dialog .inner-container');\n\n let bidContainer = biddingDialogContent.querySelector('.bids');\n const currentScrollPosition = bidContainer?.scrollTop;\n\n biddingDialogContent.innerHTML = biddingHtml;\n\n bidContainer = biddingDialogContent.querySelector('.bids');\n if(!!bidContainer) {\n bidContainer.scrollTop = currentScrollPosition;\n }\n } finally {\n loading = false;\n }\n};\n\nconst dialogOpened = ({ detail: { dialog } }) => {\n if(dialog.element.id !== 'bidding-dialog') {\n return;\n }\n\n updateHandle = setInterval(updateBiddingInformation, BiddingRefreshIntervalInMilliseconds);\n};\n\nconst dialogClosed = ({ detail: { dialog } }) => {\n if(dialog.element.id !== 'bidding-dialog') {\n return;\n }\n\n if(!!updateHandle) {\n clearInterval(updateHandle);\n }\n};\n\nexport default () => {\n if(!configuration.estate.showBids) {\n return;\n }\n\n postbox.addEventListener('dialog-opened', dialogOpened);\n postbox.addEventListener('dialog-closed', dialogClosed);\n};\n","import postbox from '../../postbox.mjs';\nimport configuration from '../../configuration.mjs';\nimport { verifyPropertyExists } from '../../utils/verify-property-exists.mjs';\n\nexport default () => {\n postbox.addEventListener('dialog-opened', ({ detail: { dialog, sourceElement } }) => {\n if(dialog.element.id !== 'book-showing-dialog') {\n return;\n }\n\n if(!verifyPropertyExists(window, 'epi', 'EPiServer', 'Forms')) {\n return;\n }\n\n const formElement = dialog.element.querySelector('form');\n\n if(!formElement) {\n return;\n }\n\n const targetShowingId = sourceElement.dataset.showingId;\n if(!!targetShowingId) {\n preselectOption(formElement, 'ShowingInformation', targetShowingId);\n }\n\n const officeID = configuration.office?.id;\n if(!!officeID) {\n preselectOption(formElement, 'OfficeId', officeID);\n }\n });\n};\n\n/**\n * @param {HTMLElement} formElement\n * @param {string} selectFriendlyName\n * @param {string} targetOptionValue\n */\nconst preselectOption = (formElement, selectFriendlyName, targetOptionValue) => {\n const forms = window.epi.EPiServer.Forms;\n const currentForm = forms[formElement.id];\n\n if(!currentForm) {\n return;\n }\n\n const elementsInfo = Object\n .keys(currentForm.ElementsInfo)\n .map(key => ({ key: key, ...currentForm.ElementsInfo[key]}));\n\n selectFriendlyName = selectFriendlyName.toLowerCase();\n\n const selectElementInfo = elementsInfo.find(x => x.friendlyName?.toLowerCase() === selectFriendlyName);\n\n if(!selectElementInfo) {\n return;\n }\n\n const selectElement = document.querySelector(`select[name=\"${selectElementInfo.key}\"]`);\n\n if(!selectElement) {\n return;\n }\n\n const options = [...selectElement.options];\n const targetOption = options.find(x => x.value.startsWith(targetOptionValue));\n\n if(!targetOption) {\n return;\n }\n\n selectElement.value = targetOption.value;\n};\n","/**\n * @param {Element} rootElement\n */\nexport default async(rootElement = document.body) => {\n const factsRoot = rootElement.querySelector('.facts');\n\n if(!factsRoot) {\n return;\n }\n\n factsRoot.addEventListener('click', event => {\n const targetElement = event.target;\n const listItem = targetElement.closest('li');\n\n if(targetElement.nodeName !== 'BUTTON' || !listItem) {\n return;\n }\n\n toggleElement(listItem);\n });\n\n const hiddenElements = factsRoot.querySelectorAll('.section-facts[hidden=\"until-found\"]');\n for(const hiddenElement of hiddenElements) {\n hiddenElement.addEventListener('beforematch', event => {\n const targetElement = event.target;\n const listItem = targetElement.closest('li');\n\n toggleElement(listItem);\n });\n }\n};\n\nconst toggleElement = listItem => {\n const button = listItem.querySelector(':scope > .section-type button');\n const factsElement = listItem.querySelector('.section-facts');\n if(!factsElement || !button) {\n return;\n }\n\n if(factsElement.hasAttribute('hidden')) {\n factsElement.removeAttribute('hidden');\n button.setAttribute('aria-expanded', 'true');\n } else {\n factsElement.setAttribute('hidden', 'until-found');\n button.setAttribute('aria-expanded', 'false');\n }\n};\n","import postbox from '../../postbox.mjs';\nimport { selectTab } from '../../page-scripts/tabs.mjs';\n\nexport default () => {\n\n postbox.addEventListener('dialog-opened', ({ detail: { dialog, sourceElement } }) => {\n if(dialog.element.id !== 'image-dialog') {\n return;\n }\n\n const selectTabId = sourceElement.dataset.selectTab;\n const tabList = dialog.element.querySelector('[role=\"tablist\"]');\n const tab = tabList?.querySelector(`[role=\"tab\"][id=\"${selectTabId}\"`);\n if(!tab) {\n return;\n }\n\n selectTab(tab, true);\n\n const scrollAnchor = sourceElement.dataset.scrollAnchor;\n if(!scrollAnchor) {\n return;\n }\n\n const targetImage = document.getElementById(scrollAnchor);\n if(!targetImage) {\n return;\n }\n\n targetImage.scrollIntoView({ behavior: 'instant' });\n });\n\n postbox.addEventListener('tab-selected', ({ detail: { tablist } }) => {\n if(tablist.id !== 'image-dialog-tablist') {\n return;\n }\n\n const dialogContent = document.getElementById('image-dialog-content');\n if(!dialogContent) {\n return;\n }\n\n dialogContent.scrollTop = 0;\n });\n};\n","import { getPageLanguage } from '../../utils/get-page-language.mjs';\nimport configuration from '../../configuration.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default async(rootElement = document.body) => {\n const projectEstatesContainer = rootElement.querySelector('#project-estates-container');\n if(!projectEstatesContainer) {\n return;\n }\n\n const showAllProjectestatesButton = projectEstatesContainer.querySelector('.show-all-estates-button');\n if(!!showAllProjectestatesButton) {\n showAllProjectestatesButton.addEventListener('click', () => {\n projectEstatesContainer.classList.add('show-all-estates');\n });\n }\n\n const culture = getPageLanguage();\n const estateShortId = configuration.estate.shortId;\n\n const url = `/api/${culture}/estate/${estateShortId}/project-estates`;\n const response = await fetch(url);\n const items = await response.json();\n\n const table = projectEstatesContainer.querySelector('table');\n const tableBody = table.querySelector('tbody');\n\n for(const item of items) {\n const row = document.createElement('tr');\n let html = `\n ${item.itemNumber || ''}\n ${item.livingArea || ''}\n ${item.numberOfRooms || ''}\n ${item.monthlyFee || ''}\n ${item.price || ''}\n ${item.status || ''}`;\n\n if(!!item.url && !!item.linkText) {\n html += `${item.linkText}`;\n } else {\n html += '';\n }\n\n row.innerHTML = html;\n\n tableBody.appendChild(row);\n }\n\n if(items.length > 5) {\n showAllProjectestatesButton.classList.add('show');\n }\n};\n","import { getPageLanguage } from '../../utils/get-page-language.mjs';\nimport applyAnchorContainer from './../../page-scripts/anchor-container.mjs';\nimport configuration from '../../configuration.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default async(rootElement = document.body) => {\n const similarEstatesContainer = rootElement.querySelector('#similar-estates-container');\n if(!similarEstatesContainer) {\n return;\n }\n\n const culture = getPageLanguage();\n const estateShortId = configuration.estate.shortId;\n\n const url = `/api/${culture}/estate/${estateShortId}/similar-estates`;\n const response = await fetch(url);\n if(!response.ok) {\n return;\n }\n\n const html = await response.text();\n\n similarEstatesContainer.innerHTML = html;\n\n applyAnchorContainer();\n};\n","import initBiddingDialog from './estate-page/bidding-dialog.mjs';\nimport initBookShowingDialog from './estate-page/book-showing-dialog.mjs';\nimport initFactsSection from './estate-page/facts.mjs';\nimport initImageDialog from './estate-page/image-dialog.mjs';\nimport initProjectEstates from './estate-page/project-estates.mjs';\nimport initSimilarEstates from './estate-page/similar-estates.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default (rootElement = document.body) => {\n const pageElement = rootElement?.querySelector('#estate-page');\n\n if(!pageElement) {\n return;\n }\n\n initBiddingDialog();\n initBookShowingDialog();\n initFactsSection(pageElement);\n initImageDialog();\n initProjectEstates(pageElement);\n initSimilarEstates(pageElement);\n};\n","export let generateUUID = function generateUUID() {\n // The \"4\" in the below string says that this UUID was randomly generated\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(char) {\n if(char === 'y') {\n const allowedYValues = ['8', '9', 'a', 'b'];\n return allowedYValues[Math.floor(Math.random() * allowedYValues.length)];\n }\n\n const array = new Uint8Array(1);\n window.crypto.getRandomValues(array);\n return (array[0] % 16).toString(16);\n });\n};\n","import Combobox from '../../utils/combobox.mjs';\nimport { debounce } from '../../utils/debounce.mjs';\nimport { generateUUID } from '../../utils/generate-uuid.mjs';\nimport { getPageLanguage } from '../../utils/get-page-language.mjs';\n\nconst SEARCH_DEBOUNCE_TIMEOUT = 50;\nconst MINIMUM_NUMBER_OF_CHARS = 3;\n\nexport default class FreetextAutocompleteCombobox extends Combobox {\n /**\n * @type {AbortController}\n */\n #abortController = null;\n #debouncedFetchAutocomplete = debounce(this.#fetchSuggestions.bind(this), SEARCH_DEBOUNCE_TIMEOUT);\n\n /**\n * @param {HTMLElement} comoboxElement\n * @param {HTMLElement} listboxElement\n */\n constructor(comoboxElement, listboxElement) {\n super(comoboxElement, listboxElement);\n\n this.#init();\n }\n\n #init() {\n this.comboboxElement.addEventListener('input', e => {\n const searchTerm = e.target.value;\n if(searchTerm.length < MINIMUM_NUMBER_OF_CHARS) {\n this.close();\n return;\n }\n\n this.#debouncedFetchAutocomplete(searchTerm, result => this.#updateSuggestions(result));\n });\n\n this.addEventListener('item-selected', this.#handleItemSelected.bind(this));\n }\n\n #reset() {\n this.comboboxElement.value = '';\n this.listboxElement.innerHTML = '';\n\n this.close();\n }\n\n #handleItemSelected(event) {\n const itemElement = event.detail.element;\n\n const field = itemElement.dataset.field;\n if(field === 'Estate') {\n const estateId = itemElement.dataset.estateId;\n window.location.href = `?estateId=${estateId}`;\n return;\n }\n\n const addFilterEvent = new CustomEvent('add-filter', {\n detail: {\n field: itemElement.dataset.field,\n value: itemElement.dataset.value,\n label: itemElement.dataset.label\n }\n });\n\n this.dispatchEvent(addFilterEvent);\n\n this.#reset();\n }\n\n async #fetchSuggestions(searchTerm, callback) {\n if(this.#abortController !== null) {\n this.#abortController.abort();\n }\n\n this.#abortController = new AbortController();\n const signal = this.#abortController.signal;\n\n const culture = getPageLanguage();\n const url = `/api/${culture}/estate-search/autocomplete?term=${encodeURIComponent(searchTerm)}`;\n\n let response;\n try {\n response = await fetch(url, { signal });\n } catch(error) {\n if(error.name === 'AbortError') {\n return;\n }\n\n throw error;\n }\n\n if(!response.ok) {\n console.error(`Failed to fetch autocomplete result: ${response.status} ${response.statusText}`);\n return;\n }\n\n const result = await response.json();\n callback(result);\n }\n\n #updateSuggestions(result) {\n if(!result) {\n return;\n }\n\n let suggestions = [\n ...result.areas,\n ...result.counties,\n ...result.municipalities,\n ...result.estateLinks\n ]\n .map(suggestion => ({\n ...suggestion,\n completeLabel: !!suggestion.secondaryLabel ? `${suggestion.label} (${suggestion.secondaryLabel})` : suggestion.label,\n uuid: generateUUID()\n }));\n\n this.#renderSuggestions(suggestions);\n }\n\n #renderSuggestions(suggestions = []) {\n const comboboxElement = this.comboboxElement;\n const listboxElement = this.listboxElement;\n\n listboxElement.innerHTML = '';\n\n if(comboboxElement.value.length < MINIMUM_NUMBER_OF_CHARS) {\n return;\n }\n\n if(suggestions.length === 0 && comboboxElement.value.length >= MINIMUM_NUMBER_OF_CHARS) {\n const listItem = document.createElement('li');\n listItem.innerText = listboxElement.dataset.noSuggestionsText;\n listItem.setAttribute('role', 'option');\n listItem.setAttribute('aria-selected', 'false');\n listItem.setAttribute('aria-disabled', 'true');\n listItem.classList.add('no-results');\n\n listboxElement.appendChild(listItem);\n return;\n }\n\n const getPriceText = (estateLink) => {\n if(!estateLink.price) {\n return '';\n }\n\n const formattedPrice = estateLink.price.toLocaleString('sv-SE');\n\n if(estateLink.currency === 'EUR') {\n return `€${formattedPrice}`;\n } else {\n return `${formattedPrice} kr`;\n }\n };\n\n suggestions.forEach(item => {\n const listItem = document.createElement('li');\n listItem.id = `autocomplete-item-${item.uuid}`;\n listItem.dataset.uuid = item.uuid;\n listItem.setAttribute('role', 'option');\n\n if(item.field === 'Estate') {\n listItem.classList.add('estate-link');\n\n if(!!item.imageUrl) {\n const img = document.createElement('img');\n img.src = item.imageUrl + '?width=100&height=100&crop=1';\n listItem.appendChild(img);\n }\n\n const address = document.createElement('span');\n address.classList.add('address');\n address.innerText = [ item.streetAddress, item.city].join(', ');\n listItem.appendChild(address);\n\n const price = document.createElement('span');\n price.classList.add('price');\n price.innerText = getPriceText(item);\n listItem.appendChild(price);\n\n listItem.dataset.field = item.field;\n listItem.dataset.estateId = item.id;\n } else {\n listItem.innerText = item.completeLabel;\n\n listItem.dataset.field = item.field;\n listItem.dataset.value = item.value;\n listItem.dataset.label = item.completeLabel;\n }\n\n listboxElement.appendChild(listItem);\n });\n\n this.open();\n }\n}\n","/**\n * Checks if a string is null or empty or if it only consists of whitespace.\n * @param {string} input The string to test.\n * @returns {boolean} True if the string is null or empty or if it only consists of whitespace, otherwise false.\n * @example\n * isNullorWhiteSpace() // true\n * isNullorWhiteSpace('') // true\n * isNullorWhiteSpace(' ') // true\n * isNullorWhiteSpace('\\t') // true\n * isNullorWhiteSpace(null) // true\n * isNullorWhiteSpace('foo') // false\n * isNullorWhiteSpace(' foo ') // false\n */\nexport let isNullOrWhiteSpace = input => {\n return !input || input.match(/^\\s*$/) !== null;\n};\n","// Polyfill needeed for Safari 13...\nimport EventTarget from '@ungap/event-target';\nimport { isNullOrWhiteSpace } from '../../utils/string-utils.mjs';\nimport postbox from '../../postbox.mjs';\n\nexport default class SearchFormHandler extends EventTarget {\n /**\n * @type {HTMLFormElement}\n */\n #form;\n\n #currentPageIndex = 0;\n #currentPageSize = 18;\n\n constructor(containerElement) {\n super();\n\n this.#form = containerElement.querySelector('form');\n this.#currentPageIndex = this.#form.dataset.startingPageIndex || 0;\n this.#currentPageSize = this.#form.dataset.pageSize || 18;\n\n this.#init();\n }\n\n get form() {\n return this.#form;\n }\n\n #init() {\n this.#form.addEventListener('change', this.handleFormChange.bind(this));\n this.#form.addEventListener('submit', this.#handleFormSubmit.bind(this));\n\n postbox.addEventListener('request-next-page', this.#handleRequestNextPage.bind(this));\n }\n\n #handleFormSubmit(event) {\n event.preventDefault();\n }\n\n #handleRequestNextPage() {\n this.#currentPageIndex++;\n\n const formData = this.#getCleanFormData();\n\n formData.set('pageIndex', this.#currentPageIndex.toString());\n\n postbox.dispatchEvent(new CustomEvent('search-query-changed', { detail: { query: formData } }));\n\n this.#updateRestoreToQueryString();\n }\n\n #updateRestoreToQueryString() {\n const formData = this.#getCleanFormData();\n const pageIndex = this.#currentPageIndex;\n const pageSize = this.#currentPageSize;\n\n formData.set('restoreTo', (pageIndex + 1) * pageSize);\n formData.delete('pageIndex');\n\n const restoreUrl = this.#buildUrl(formData);\n\n this.#updateUrl(restoreUrl);\n }\n\n handleFormChange() {\n this.#currentPageIndex = 0;\n\n const formData = this.#getCleanFormData();\n\n const url = this.#buildUrl(formData);\n\n this.#updateUrl(url);\n\n postbox.dispatchEvent(new CustomEvent('search-query-changed', { detail: { query: formData } }));\n }\n\n #updateUrl(url) {\n const state = { url };\n const title = window.title;\n history.replaceState(state, title, url);\n }\n\n #getCleanFormData() {\n const formData = new FormData(this.#form);\n\n const keys = [...formData.keys()];\n\n for(const key of keys) {\n const value = formData.get(key);\n if(isNullOrWhiteSpace(value)) {\n formData.delete(key);\n }\n }\n\n return formData;\n }\n\n #buildUrl(formData) {\n const baseUrl = this.#form.action;\n const urlParts = this.getUrlParts(formData)\n .filter(x => !isNullOrWhiteSpace(x))\n .map(x => encodeURIComponent(x));\n\n const querystring = this.#toQueryString(formData);\n\n return baseUrl + urlParts.join('/') + querystring;\n }\n\n // eslint-disable-next-line no-unused-vars\n getUrlParts(formData) {\n console.warn('Should be implemented by subclass.');\n return [];\n }\n\n getEstateTypeForUrl(formData) {\n const estateType = formData.get('typeId');\n\n if(isNullOrWhiteSpace(estateType)) {\n return null;\n }\n\n const estateTypesContainer = this.#form.querySelector('#estate-types');\n const estateTypeCheckbox = estateTypesContainer.querySelector(`input[value=\"${estateType}\"]`);\n const estateTypeElement = estateTypeCheckbox.parentElement;\n\n return this.getCleanedUrlPart(estateTypeElement.textContent);\n }\n\n getCleanedUrlPart(label) {\n if(!label) {\n return null;\n }\n\n return label\n .trim()\n .replace(/\\(.*?\\)/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-$/, '');\n }\n\n #toQueryString(formData) {\n const params = new URLSearchParams(formData);\n\n const keys = [...params.keys()];\n if(keys.length === 0) {\n return '';\n }\n\n return '?' + params.toString();\n }\n\n // Exposed only for testing purposes..\n buildUrl(/** @type {FormData} */ formData) {\n return this.#buildUrl(formData);\n }\n}\n","import SearchFormHandlerBase from './search-form-handler-base.mjs';\nimport { isNullOrWhiteSpace } from '../../utils/string-utils.mjs';\nimport AutocompleteHandler from './freetext-autocomplete-combobox.mjs'; // eslint-disable-line no-unused-vars\n\nexport default class SwedishSearchFormHandler extends SearchFormHandlerBase {\n /**\n * @type {AutocompleteHandler}\n */\n #autocompleteHandler;\n\n #geographicalFilterContainer = null;\n #geographicalFilterTemplate = null;\n\n constructor(containerElement, autocompleteHandler) {\n super(containerElement);\n\n if(!autocompleteHandler) {\n throw new Error('autocompleteHandler must be provided.');\n }\n\n this.#autocompleteHandler = autocompleteHandler;\n\n this.#geographicalFilterContainer = containerElement.querySelector('#geographical-filters');\n this.#geographicalFilterTemplate = containerElement.querySelector('#geographical-filter-template');\n\n this.#init();\n }\n\n #init() {\n this.#autocompleteHandler.addEventListener('add-filter', event => {\n this.#addGeographicalFilter(event.detail.field, event.detail.label, event.detail.value);\n });\n\n this.#geographicalFilterContainer.addEventListener('change', this.#handleGeographialFilterRemoval.bind(this));\n }\n\n #addGeographicalFilter(field, labelValue, value) {\n const existingFilters = [...this.#geographicalFilterContainer.querySelectorAll(`input[name=\"${field}\"]`)];\n if(existingFilters.length > 0) {\n const newValueAlreadyExists = existingFilters.some(filter => filter.value === value);\n if(newValueAlreadyExists) {\n return;\n }\n }\n\n const container = this.#geographicalFilterContainer;\n\n const templateRoot = this.#geographicalFilterTemplate.content.cloneNode(true);\n\n const inputValue = templateRoot.querySelector('input[type=\"checkbox\"]');\n inputValue.name = field;\n inputValue.value = value;\n\n const inputLabel = templateRoot.querySelector('input[type=\"hidden\"]');\n inputLabel.name = `${field}-${value}-label`;\n inputLabel.value = labelValue;\n\n const span = templateRoot.querySelector('span');\n span.innerText = labelValue;\n\n container.appendChild(templateRoot);\n\n this.handleFormChange();\n }\n\n #handleGeographialFilterRemoval(event) {\n const checkbox = event.target;\n if(checkbox.type !== 'checkbox') {\n return;\n }\n\n // This shouldn't really happen, but just in case...\n if(checkbox.checked) {\n return;\n }\n\n if(checkbox.name === 'sold') {\n const comingSoonSelect = document.getElementById('coming-soon');\n if(!!comingSoonSelect) {\n comingSoonSelect.disabled = false;\n }\n }\n\n checkbox.parentElement.parentElement.remove();\n }\n\n getUrlParts(formData) {\n return [\n this.getEstateTypeForUrl(formData),\n this.#getMunicipalityForUrl(formData),\n this.#getAreaForUrl(formData)\n ];\n }\n\n #getMunicipalityForUrl(/** @type {FormData} */ formData) {\n const municipalityId = formData.get('municipalityId');\n\n if(isNullOrWhiteSpace(municipalityId)) {\n return null;\n }\n\n return this.getCleanedUrlPart(formData.get(`municipalityId-${municipalityId}-label`));\n }\n\n #getAreaForUrl(/** @type {FormData} */ formData) {\n const areaId = formData.get('areaId');\n\n if(isNullOrWhiteSpace(areaId)) {\n return null;\n }\n\n return this.getCleanedUrlPart(formData.get(`areaId-${areaId}-label`));\n }\n}\n","import FreetextAutocompleteCombobox from './freetext-autocomplete-combobox.mjs';\nimport SwedishSearchFormHandler from './swedish-search-form-handler.mjs';\n\n/**\n * @param {Element} pageElement The estate search page root element\n */\nexport default (pageElement) => {\n if(!pageElement) {\n return;\n }\n\n const combobox = pageElement.querySelector('#freetext-autocomplete-combobox');\n const listbox = pageElement.querySelector('#freetext-autocomplete-listbox');\n\n const autocompleteHandler = new FreetextAutocompleteCombobox(combobox, listbox);\n // eslint-disable-next-line no-unused-vars\n const formHandler = new SwedishSearchFormHandler(pageElement, autocompleteHandler);\n};\n","const comparerCache = {};\n\nconst getComparer = locale => {\n if(!!comparerCache[locale]) {\n return comparerCache[locale];\n }\n\n const comparer = new Intl.Collator(locale, { sensitivity: 'accent' }).compare;\n return comparerCache[locale] = comparer;\n};\n\nconst localeCompareSupportsLocales = (function() {\n try {\n 'foo'.localeCompare('bar', 'i');\n } catch(e) {\n return e.name === 'RangeError';\n }\n return false;\n})();\n\n/**\n * @param {string} a The first string to compare\n * @param {string} b The second string to compare\n * @param {string} locale The locale to use when comparing (defaults to swedish)\n * @returns {number} -1 if a < b, 1 if a > b, 0 if a === b\n */\nexport default function localeComparer(a, b, locale = 'sv') {\n if(!a && !!b) {\n return 1;\n } else if(!!a && !b) {\n return -1;\n } else if(!a && !b) {\n return 0;\n }\n\n let shouldWarn = false;\n if(typeof a !== 'string') {\n a = a.toString();\n shouldWarn = true;\n }\n\n if(typeof b !== 'string') {\n b = b.toString();\n shouldWarn = true;\n }\n\n if(shouldWarn) {\n console.warn('Trying to compare non-string objects with localeComparer.', a, b);\n }\n\n // The regex matches a range from space to tilde, which isn't really that clear\n // but it is bacily the ASCII range\n let asciiStrings = false;\n let asciiRegex = /^[ -~]*$/;\n if(asciiRegex.test(a) && asciiRegex.test(b)) {\n asciiStrings = true;\n }\n\n if(asciiStrings || !localeCompareSupportsLocales) {\n if(a < b) {\n return -1;\n } else if(a > b) {\n return 1;\n } else {\n return 0;\n }\n }\n\n const comparer = getComparer(locale);\n return comparer(a, b);\n}\n","import Combobox from '../../utils/combobox.mjs';\nimport { firstAnscestorOrDefault } from '../../utils/dom-utils.mjs';\nimport { getPageLanguage } from '../../utils/get-page-language.mjs';\nimport localeComparer from '../../utils/locale-comparer.mjs';\n\nexport default class InternationalAreaCombobox extends Combobox {\n #inputContainerElement;\n #disabled = false;\n\n #listboxElement;\n\n /**\n * @param {HTMLElement} comboboxElement The combobox element\n * @param {HTMLElement} listboxElement The listbox element\n * @param {HTMLElement} inputContainerElement The input container element\n */\n constructor(comboboxElement, listboxElement, inputContainerElement) {\n super(comboboxElement, listboxElement);\n\n if(!(inputContainerElement instanceof HTMLElement)) {\n throw new Error('inputContainerElement must be an HTMLElement.');\n }\n\n this.#inputContainerElement = inputContainerElement;\n this.#listboxElement = listboxElement;\n\n this.#disabled = this.#inputContainerElement.classList.contains('disabled');\n\n this.#setupEventListeners();\n }\n\n get hasSelectedItems() {\n return this.selectedInputs.length > 0;\n }\n\n get selectedInputs() {\n return [...this.#inputContainerElement.querySelectorAll('.multiselect-selected-options input:checked')];\n }\n\n #setupEventListeners() {\n const inputContainer = this.#inputContainerElement;\n\n inputContainer.addEventListener('change', event => {\n const input = event.target;\n if(!(input instanceof HTMLInputElement)) {\n throw new Error('input must be an HTMLInputElement.');\n }\n\n if(input.type !== 'checkbox') {\n return;\n }\n\n if(input.readOnly) {\n input.checked = true;\n event.stopPropagation();\n return;\n }\n\n const multiselectOptionId = input.dataset.multiselectOptionId;\n if(!multiselectOptionId) {\n throw new Error('multiselectOptionId must be set.');\n }\n\n // This one isn't always available due to dynamicly removed items.\n const listboxItem = this.listboxElement.querySelector(`#${multiselectOptionId}`);\n listboxItem?.setAttribute('aria-selected', 'false');\n\n const inputParentListItem = firstAnscestorOrDefault(input, x => x.tagName === 'LI');\n inputParentListItem.remove();\n\n this.#dispatchChangeEvent();\n });\n\n this.addEventListener('item-selected', event => {\n const element = event.detail.element;\n\n const { filterField, filterLabel, filterValue } = element.dataset;\n\n const templateElement = this.#inputContainerElement.querySelector('template[data-template-name=\"selected-filter\"]');\n const templateRoot = templateElement.content.cloneNode(true);\n\n const input = templateRoot.querySelector('input');\n input.name = filterField;\n input.value = filterValue;\n input.dataset.multiselectOptionId = element.id;\n\n const label = templateRoot.querySelector('span');\n label.textContent = filterLabel;\n\n const selectedOptionsList = this.#inputContainerElement.querySelector('.multiselect-selected-options');\n\n const language = getPageLanguage();\n const options = [...selectedOptionsList.children];\n\n let insertAtIndex = 0;\n for(const [index, option] of options.entries()) {\n const textContent = option.textContent.trim();\n\n const compareResult = localeComparer(textContent, filterValue, language);\n\n if(compareResult !== 1) {\n insertAtIndex = index + 1;\n }\n }\n\n selectedOptionsList.insertBefore(templateRoot, selectedOptionsList.children[insertAtIndex]);\n\n this.#dispatchChangeEvent();\n });\n\n this.addEventListener('item-deselected', event => {\n const element = event.detail.element;\n\n const optionId = element.id;\n if(!optionId) {\n throw new Error('option id must be set.');\n }\n\n const input = this.#inputContainerElement.querySelector(`input[data-multiselect-option-id=\"${optionId}\"]`);\n if(!input) {\n throw new Error(`input with data-multiselect-option-id ${optionId} not found.`);\n }\n\n const inputParentListItem = firstAnscestorOrDefault(input, x => x.tagName === 'LI');\n inputParentListItem.remove();\n\n this.#dispatchChangeEvent();\n });\n }\n\n updateItems(items) {\n const listboxElement = this.#listboxElement;\n while(!!listboxElement.firstChild) {\n listboxElement.removeChild(listboxElement.lastChild);\n }\n\n this.#createItemGroups(listboxElement, items);\n }\n\n #createItemGroups(listboxElement, groups) {\n const templateElement = this.#inputContainerElement.parentElement.querySelector('template[data-template-name=\"filter-group\"]');\n\n for(const group of groups) {\n const templateRoot = templateElement.content.cloneNode(true);\n\n const list = templateRoot.querySelector('ul');\n list.setAttribute('aria-labelledby', `multiselect-group-${group.groupId}`);\n\n const label = list.querySelector('.group-label');\n label.id = `multiselect-group-${group.groupId}`;\n label.textContent = group.label;\n\n this.#createItemsInGroup(list, group.values);\n\n listboxElement.appendChild(templateRoot);\n }\n }\n\n #createItemsInGroup(groupElement, items) {\n const templateElement = this.#inputContainerElement.parentElement.querySelector('template[data-template-name=\"filter-item\"]');\n\n for(const item of items) {\n const templateRoot = templateElement.content.cloneNode(true);\n\n const listItem = templateRoot.querySelector('li');\n listItem.id = `multiselect-list-item-${item.filterId}`;\n listItem.dataset.filterField = item.filterField;\n listItem.dataset.filterLabel = item.label;\n listItem.dataset.filterValue = item.value;\n listItem.setAttribute('aria-selected', item.selected ? 'true' : 'false');\n\n const label = listItem.querySelector('.label-text');\n label.textContent = item.label;\n\n groupElement.appendChild(templateRoot);\n }\n }\n\n enable() {\n if(!this.#disabled) {\n return;\n }\n\n this.#disabled = false;\n this.#updateDisabledAttributes();\n }\n\n disable() {\n if(this.#disabled) {\n return;\n }\n\n this.#disabled = true;\n this.#updateDisabledAttributes();\n }\n\n #dispatchChangeEvent() {\n const event = new CustomEvent('selected-items-changed', {\n detail: {\n sender: this\n }\n });\n\n this.dispatchEvent(event);\n }\n\n #updateDisabledAttributes() {\n const disabled = this.#disabled;\n const inputContainerElement = this.#inputContainerElement;\n\n const comboboxElement = inputContainerElement.querySelector('.multiselect-combobox');\n const selectedOptions = inputContainerElement.querySelectorAll('.multiselect-selected-options input');\n\n if(disabled) {\n inputContainerElement.classList.add('disabled');\n comboboxElement.setAttribute('aria-disabled', 'true');\n } else {\n inputContainerElement.classList.remove('disabled');\n comboboxElement.setAttribute('aria-disabled', 'false');\n }\n\n for(const selectedOption of selectedOptions) {\n selectedOption.readOnly = disabled;\n }\n }\n}\n","import EventTarget from '@ungap/event-target';\n\nexport default class CountrySelectWrapper extends EventTarget {\n #selectElement;\n #hiddenFallbackElement;\n\n /**\n * @param {HTMLSelectElement} selectElement The select element\n */\n constructor(selectElement) {\n super();\n\n if(!(selectElement instanceof HTMLSelectElement)) {\n throw new Error('selectElement must be an HTMLElement.');\n }\n\n const hiddenFallbackElement = selectElement.parentElement.querySelector('input[type=\"hidden\"]');\n if(!(hiddenFallbackElement instanceof HTMLInputElement)) {\n throw new Error('hiddenFallbackElement must be an HTMLInputElement.');\n }\n\n this.#selectElement = selectElement;\n this.#hiddenFallbackElement = hiddenFallbackElement;\n\n this.#selectElement.addEventListener('change', this.#handleSelectChange.bind(this));\n }\n\n #handleSelectChange() {\n const event = new CustomEvent('selected-items-changed', {\n detail: {\n sender: this\n }\n });\n\n this.dispatchEvent(event);\n }\n\n enable() {\n this.#selectElement.disabled = false;\n this.#hiddenFallbackElement.value = '';\n }\n\n disable() {\n this.#selectElement.disabled = true;\n\n const seletedOption = this.#selectElement.querySelector('option:checked');\n this.#hiddenFallbackElement.value = seletedOption.value;\n }\n}\n","import InternationalAreaCombobox from './international-area-combobox.mjs';\nimport SearchFormHandlerBase from './search-form-handler-base.mjs';\nimport { getPageLanguage } from '../../utils/get-page-language.mjs';\nimport { isNullOrWhiteSpace } from '../../utils/string-utils.mjs';\n\nexport default class InternationalSearchFormHandler extends SearchFormHandlerBase {\n /**\n * @type {InternationalAreaCombobox[]}\n */\n #multiselects = [];\n\n /**\n * @type {AbortController}\n */\n #abortController = null;\n\n constructor(containerElement, multiselects) {\n super(containerElement);\n\n if(!Array.isArray(multiselects)) {\n throw new Error('multiselects must be provided as an array.');\n }\n\n this.#multiselects = multiselects;\n\n this.#init();\n }\n\n #init() {\n const multiselects = this.#multiselects;\n\n for(const { combobox } of multiselects) {\n combobox.addEventListener('selected-items-changed', this.handleFormChange.bind(this));\n combobox.addEventListener('selected-items-changed', this.#updateAvailability.bind(this));\n combobox.addEventListener('selected-items-changed', this.#fetchNewSuggestions.bind(this));\n }\n\n const referenceNumberButton = document.getElementById('search-reference-number-button');\n referenceNumberButton.addEventListener('click', this.#handleReferenceNumberButtonClick.bind(this));\n }\n\n /**\n * @param {Event} event\n */\n async #handleReferenceNumberButtonClick(event) {\n event.preventDefault();\n event.stopPropagation();\n\n const errorMessageElement = document.getElementById('estate-not-found-message');\n errorMessageElement.classList.remove('show');\n\n const referenceNumberInput = document.getElementById('reference-number');\n const referenceNumber = referenceNumberInput.value;\n if(isNullOrWhiteSpace(referenceNumber)) {\n return;\n }\n\n let abortController = this.#abortController;\n if(abortController !== null) {\n abortController.abort();\n }\n\n this.#abortController = abortController = new AbortController();\n\n const culture = getPageLanguage();\n const url = `/api/${culture}/estate-search/by-reference-number/${encodeURIComponent(referenceNumber)}`;\n\n let response;\n try {\n response = await fetch(url, { signal: abortController.signal });\n } catch(error) {\n if(error.name === 'AbortError') {\n return;\n }\n\n throw error;\n }\n\n if(!response.ok) {\n if(response.status === 404) {\n errorMessageElement.classList.add('show');\n return;\n }\n\n console.error(`Failed to fetch estate by reference number: ${response.status} ${response.statusText}`);\n return;\n }\n\n const result = await response.text();\n window.location.href = result;\n }\n\n getUrlParts(formData) {\n return [\n this.#getCountryForUrl(),\n this.getEstateTypeForUrl(formData),\n ...this.#getGeographicalFiltersForUrl(formData)\n ];\n }\n\n #getCountryForUrl() {\n const countryElement = document.getElementById('country');\n\n const selectedOption = countryElement.querySelector('option:checked');\n if(!selectedOption) {\n return null;\n }\n\n return selectedOption.textContent;\n }\n\n #getGeographicalFiltersForUrl(formData) {\n const province = this.#getGeographicalFilterlabel(formData, 'foreignGeoDataProvince');\n const city = this.#getGeographicalFilterlabel(formData, 'foreignGeoDataCity');\n const cityArea = this.#getGeographicalFilterlabel(formData, 'foreignGeoDataCityArea');\n\n const result = [];\n\n if(!!province) {\n result.push(province);\n }\n\n if(!!city) {\n result.push(city);\n }\n\n if(!!cityArea) {\n result.push(cityArea);\n }\n\n return result;\n }\n\n #getGeographicalFilterlabel(formData, field) {\n const value = formData.get(field);\n if(!value) {\n return null;\n }\n\n const selectedInputs = this.#multiselects.flatMap(x => x.combobox.selectedInputs).filter(x => !!x);\n const selectedInput = selectedInputs.find(x => x.name === field && x.value === value);\n if(!selectedInput) {\n return value;\n }\n\n return selectedInput.parentElement.textContent.trim();\n }\n\n #getFormData() {\n const form = this.form;\n const formData = new FormData(form);\n\n const queryFields = [\n 'country',\n 'foreignGeoDataProvince',\n 'foreignGeoDataCity',\n 'foreignGeoDataCityArea'\n ];\n\n for(const [ field ] of [...formData]) {\n if(!queryFields.includes(field)) {\n formData.delete(field);\n }\n }\n\n return formData;\n }\n\n #updateAvailability() {\n for(const { combobox, dependsOn } of this.#multiselects) {\n const shouldBeDisabled = dependsOn.some(x => x.hasSelectedItems);\n if(shouldBeDisabled) {\n combobox.disable();\n } else {\n combobox.enable();\n }\n }\n }\n\n async #fetchNewSuggestions() {\n let abortController = this.#abortController;\n if(abortController !== null) {\n abortController.abort();\n }\n\n this.#abortController = abortController = new AbortController();\n\n const culture = getPageLanguage();\n const formData = this.#getFormData();\n const url = `/api/${culture}/estate-search/foreign-areas?${new URLSearchParams(formData)}`;\n\n let response;\n try {\n response = await fetch(url, { signal: abortController.signal });\n } catch(error) {\n if(error.name === 'AbortError') {\n return;\n }\n\n throw error;\n }\n\n if(!response.ok) {\n console.error(`Failed to fetch autocomplete result: ${response.status} ${response.statusText}`);\n return;\n }\n\n const result = await response.json();\n\n const provinceCombobox = this.#multiselects.find(x => x.name === 'province').combobox;\n provinceCombobox.updateItems(result.provinces);\n\n const cityCombobox = this.#multiselects.find(x => x.name === 'city').combobox;\n cityCombobox.updateItems(result.cities);\n\n const cityAreaCombobox = this.#multiselects.find(x => x.name === 'city-area').combobox;\n cityAreaCombobox.updateItems(result.cityAreas);\n }\n}\n","import InternationalAreaCombobox from './international-area-combobox.mjs';\nimport CountrySelectWrapper from './country-select-wrapper.mjs';\nimport { firstAnscestorOrDefault } from '../../utils/dom-utils.mjs';\nimport InternationalSearchFormHandler from './international-search-form-handler.mjs';\n\n/**\n * @param {Element} pageElement The estate search page root element\n */\nexport default (pageElement) => {\n if(!pageElement) {\n return;\n }\n\n const countrySelectElement = pageElement.querySelector('#country');\n const countrySelect = new CountrySelectWrapper(countrySelectElement);\n\n const provinceComboboxElement = pageElement.querySelector('#multiselect-province-combobox');\n const provinceCombobox = getCombobox(getComboboxContainerElement(provinceComboboxElement));\n\n const cityComboboxElement = pageElement.querySelector('#multiselect-city-combobox');\n const cityCombobox = getCombobox(getComboboxContainerElement(cityComboboxElement));\n\n const cityAreaComboboxElement = pageElement.querySelector('#multiselect-city-area-combobox');\n const cityAreaCombobox = getCombobox(getComboboxContainerElement(cityAreaComboboxElement));\n\n const multiselects = [\n { name: 'country', combobox: countrySelect, dependsOn: [ provinceCombobox, cityCombobox, cityAreaCombobox] },\n { name: 'province', combobox: provinceCombobox, dependsOn: [ cityCombobox, cityAreaCombobox] },\n { name: 'city', combobox: cityCombobox, dependsOn: [ cityAreaCombobox ] },\n { name: 'city-area', combobox: cityAreaCombobox, dependsOn: [] }\n ];\n\n // eslint-disable-next-line no-unused-vars\n const formHandler = new InternationalSearchFormHandler(pageElement, multiselects);\n};\n\nconst getComboboxContainerElement = (element) => {\n return firstAnscestorOrDefault(element, x => x.classList.contains('multiselect'));\n};\n\nconst getCombobox = (containerElement) => {\n const comboboxElement = containerElement.querySelector('.multiselect-combobox');\n const listboxElement = containerElement.querySelector('.multiselect-listbox');\n const inputContainerElement = containerElement.querySelector('.input-container');\n\n const combobox = new InternationalAreaCombobox(comboboxElement, listboxElement, inputContainerElement);\n\n return combobox;\n};\n","import postbox from '../../postbox.mjs';\n\nexport default class CreateSearchAlertButtonHandler {\n /**\n * @type {HTMLButtonElement}\n */\n #button;\n\n constructor(containerElement) {\n const button = containerElement.querySelector('#search-alert-button');\n\n if(!button) {\n console.log('No search alert button found on page, most likely because there is no search alert form on the page.');\n return;\n }\n\n this.#button = button;\n\n this.#init();\n }\n\n #init() {\n postbox.addEventListener('toggle-search-alert-button', this.#handleToggleEvent.bind(this));\n }\n\n #handleToggleEvent(/** @type {CustomEvent} */ event) {\n const enableButton = event.detail.enabled;\n const disabledTooltip = this.#button.dataset.disabledTooltip;\n\n if(enableButton) {\n this.#button.disabled = false;\n this.#button.title = '';\n } else {\n this.#button.disabled = true;\n this.#button.title = disabledTooltip;\n }\n }\n}\n","// Polyfill needeed for Safari 13...\nimport EventTarget from '@ungap/event-target';\nimport postbox from '../../postbox.mjs';\nimport { debounce } from '../../utils/debounce.mjs';\nimport { getPageLanguage } from '../../utils/get-page-language.mjs';\n\nconst SEARCH_DEBOUNCE_TIMEOUT = 50;\n\nexport default class SearchResultHandler extends EventTarget {\n #container;\n #resultsList;\n #resultInfo;\n #loader;\n #showMoreContainer;\n\n #handleQueryChangedBound = null;\n\n /**\n * @type {AbortController}\n */\n #abortController = null;\n #debouncedFetchResults = debounce(this.#fetchResult.bind(this), SEARCH_DEBOUNCE_TIMEOUT);\n\n /**\n * @type {IntersectionObserver}\n */\n #intersectionObserver;\n\n constructor(containerElement) {\n super();\n\n this.#container = containerElement;\n this.#resultsList = containerElement.querySelector('#estate-results');\n this.#resultInfo = containerElement.querySelector('#results-info-container');\n this.#loader = containerElement.querySelector('#loader');\n this.#showMoreContainer = containerElement.querySelector('#show-more-container');\n this.#handleQueryChangedBound = this.#handleQueryChanged.bind(this);\n\n this.#init();\n }\n\n #init() {\n postbox.addEventListener('search-query-changed', this.#handleQueryChangedBound);\n this.#initMoreResultsButton();\n this.#initIntersectionObserver();\n }\n\n destroy() {\n postbox.removeEventListener('search-query-changed', this.#handleQueryChangedBound);\n this.#intersectionObserver.disconnect();\n }\n\n #initIntersectionObserver() {\n this.#intersectionObserver = new IntersectionObserver(entries => {\n if(entries.length > 1) {\n throw new Error('Multiple entries found, this is not supported.');\n }\n\n const entry = entries[0];\n const scrollPosition = window.scrollY;\n const hideStickyInfo = entry.isIntersecting || scrollPosition > this.#resultInfo.offsetTop;\n\n this.#resultInfo.classList.toggle('hide-sticky', hideStickyInfo);\n }, {\n root: null,\n rootMargin: '0px',\n threshold: 0.5\n });\n\n this.#intersectionObserver.observe(this.#resultInfo);\n }\n\n #initMoreResultsButton() {\n const anchor = this.#container.querySelector('#more-results-link');\n if(anchor === null) {\n return;\n }\n\n const classNames = [...anchor.classList];\n\n const button = document.createElement('button');\n button.id = anchor.id;\n button.textContent = anchor.textContent;\n button.addEventListener('click', this.#fetchNextPage.bind(this));\n\n if(classNames.length > 0) {\n button.classList.add(classNames);\n }\n\n anchor.replaceWith(button);\n }\n\n async #handleQueryChanged(event) {\n const query = event.detail.query;\n\n await this.#debouncedFetchResults(query, this.#updateResults.bind(this));\n }\n\n async #fetchNextPage() {\n postbox.dispatchEvent(new CustomEvent('request-next-page'));\n }\n\n async #fetchResult(formData, callback) {\n if(this.#abortController !== null) {\n this.#abortController.abort();\n }\n\n const requestedPageIndex = parseInt(formData.get('pageIndex'), 10) || 0;\n if(requestedPageIndex === 0) {\n this.#resultInfo.classList.add('loading');\n this.#resultsList.classList.add('loading');\n }\n\n this.toggleLoader(true);\n postbox.dispatchEvent(new CustomEvent('toggle-search-alert-button', { detail: { enabled: false } }));\n\n this.#abortController = new AbortController();\n const signal = this.#abortController.signal;\n\n const culture = getPageLanguage();\n const url = `/api/${culture}/estate-search/html?` + new URLSearchParams(formData);\n\n let response;\n try {\n response = await fetch(url, { signal });\n } catch(error) {\n if(error.name === 'AbortError') {\n return;\n }\n\n throw error;\n }\n\n this.toggleLoader(false);\n\n if(!response.ok) {\n console.error(`Failed to fetch estate result: ${response.status} ${response.statusText}`);\n return;\n }\n\n this.#showMoreResultsButton(response.headers.get('x-has-more-results') === 'True');\n this.#disableSortSelect(response.headers.get('x-disable-sorting') === 'True');\n\n const canCreateSearchAlertFromQuery = response.headers.get('x-can-create-search-alert-from-query');\n if(canCreateSearchAlertFromQuery === 'True') {\n postbox.dispatchEvent(new CustomEvent('toggle-search-alert-button', { detail: { enabled: true } }));\n }\n\n const result = await response.text();\n const pageIndex = parseInt(response.headers.get('x-page-index'), 10);\n callback(result, pageIndex);\n }\n\n toggleLoader(show) {\n this.#loader.classList.toggle('show', show);\n }\n\n #showMoreResultsButton(show) {\n this.#showMoreContainer.classList.toggle('show', show);\n }\n\n #disableSortSelect(disable) {\n const sortSelect = this.#container.querySelector('#sort');\n if(sortSelect === null) {\n return;\n }\n\n sortSelect.disabled = disable;\n }\n\n #updateResults(result, pageIndex) {\n if(pageIndex === 0) {\n this.#resultsList.innerHTML = '';\n }\n\n const tempContainer = document.createElement('div');\n tempContainer.innerHTML = result;\n\n const listItems = tempContainer.querySelector('#results').innerHTML;\n this.#resultsList.insertAdjacentHTML('beforeend', listItems);\n this.#resultsList.classList.remove('loading');\n\n const resultsInfo = tempContainer.querySelector('#results-info-container').innerHTML;\n this.#resultInfo.innerHTML = resultsInfo;\n this.#resultInfo.classList.remove('loading');\n }\n}\n","import configuration from '../configuration.mjs';\nimport initSwedishSearchForm from './estate-search-page/swedish-search-form.mjs';\nimport initInternationalSearchForm from './estate-search-page/international-search-form.mjs';\nimport CreateSearchAlertButtonHandler from './estate-search-page/create-search-alert-button-handler.mjs';\nimport SearchResultHandler from './estate-search-page/search-result-handler.mjs';\n\n/**\n * @param {Element} rootElement\n */\nexport default (rootElement = document.body) => {\n const pageElement = rootElement?.querySelector('#estate-search-page');\n\n if(!pageElement) {\n return;\n }\n\n if(configuration.website === 'Sweden') {\n initSwedishSearchForm(pageElement);\n } else if(configuration.website === 'International') {\n initInternationalSearchForm(pageElement);\n } else {\n throw new Error(`Unknown website: ${configuration.website}`);\n }\n\n new SearchResultHandler(pageElement);\n new CreateSearchAlertButtonHandler(pageElement);\n};\n","import initBrokerSearchPage from './broker-search-page.mjs';\nimport initEstatePage from './estate-page.mjs';\nimport initEstateSearchPage from './estate-search-page.mjs';\n\n/**\n * Init all scripts for specific pages\n */\nexport default function() {\n initBrokerSearchPage();\n initEstatePage();\n initEstateSearchPage();\n}\n","let focusedContainer = null;\n\nexport let lockFocus = function lockFocus(element) {\n if(focusedContainer !== null) {\n throw new Error('Element is already locked.', focusedContainer);\n }\n\n focusedContainer = element;\n document.addEventListener('focus', focusHandler, true);\n};\n\nexport let unlockFocus = function unlockFocus() {\n if(focusedContainer === null) {\n return;\n }\n\n document.removeEventListener('focus', focusHandler, true);\n focusedContainer = null;\n};\n\nconst focusHandler = function focusHandler(event) {\n if(!focusedContainer.contains(event.target)) {\n focusedContainer.focus();\n }\n};\n","/**\n * Disable scrolling of an element by setting overflow to \"hidden\".\n * @param {HTMLElement} element The element to disable scrolling for. Defaults to document.body.\n * @returns {void}\n */\nexport let lockScroll = (element = document.body) => element.style.overflow = 'hidden';\n\n/**\n * Re-enable scrolling of an element removing \"hidden\".\n * @param {HTMLElement} element The element to re-enable scrolling for. Defaults to document.body.\n * @returns {void}\n */\nexport let unlockScroll = (element = document.body) => element.style.overflow === 'hidden' ? element.style.overflow = '' : void 0;\n","import postbox from '../postbox.mjs';\nimport { firstAnscestorOrDefault } from './dom-utils.mjs';\nimport { lockFocus, unlockFocus } from './lock-focus.mjs';\nimport { lockScroll, unlockScroll } from './scroll-utils.mjs';\nimport { isNullOrWhiteSpace } from './string-utils.mjs';\n\nexport default class Dialog {\n /**\n * @type {HTMLElement}\n */\n #targetElement = null;\n\n /**\n * @type {HTMLElement}\n */\n #openedFromElement = null;\n\n #isOpen = false;\n\n #handleClickBound = null;\n #handleKeyDownBound = null;\n\n get element() {\n return this.#targetElement;\n }\n\n constructor(targetElement) {\n if(!targetElement) {\n throw new Error('targetElement is required.');\n }\n\n if(isNullOrWhiteSpace(targetElement.id)) {\n throw new Error('targetElement must have an id.');\n }\n\n this.#targetElement = targetElement;\n this.#handleClickBound = this.#handleClick.bind(this);\n this.#handleKeyDownBound = this.#handleKeyDown.bind(this);\n\n this.#initElements();\n }\n\n #initElements() {\n const targetElement = this.#targetElement;\n targetElement.setAttribute('role', 'dialog');\n targetElement.setAttribute('aria-modal', 'true');\n targetElement.setAttribute('tabindex', '-1');\n\n const header = targetElement.querySelector('h2');\n if(!!header) {\n if(isNullOrWhiteSpace(header.id)) {\n header.setAttribute('id', this.#generateUniqueElementId(`${targetElement.id}-header`));\n }\n\n targetElement.setAttribute('aria-labelledby', header.id);\n }\n\n const activatorElements = this.#getActivatorElements();\n for(const element of activatorElements) {\n element.setAttribute('aria-controls', targetElement.id);\n element.setAttribute('aria-expanded', 'false');\n }\n\n targetElement.addEventListener('click', this.#handleClickBound);\n targetElement.addEventListener('keydown', this.#handleKeyDownBound);\n }\n\n destroy() {\n this.#targetElement.removeEventListener('click', this.#handleClickBound);\n this.#targetElement.removeEventListener('keydown', this.#handleKeyDownBound);\n\n if(this.#isOpen) {\n unlockFocus();\n unlockScroll();\n }\n }\n\n #handleClick(event) {\n const targetElement = event.target;\n const elementWithDialogClose = firstAnscestorOrDefault(targetElement, element => typeof element.dataset.dialogCloseButton !== 'undefined', true);\n\n if(!!elementWithDialogClose) {\n this.close();\n }\n }\n\n #handleKeyDown(event) {\n const key = event.key;\n\n if(key === 'Escape') {\n this.close();\n }\n }\n\n open(sourceElement) {\n this.#openedFromElement = sourceElement;\n\n this.#isOpen = true;\n this.#updateElements();\n }\n\n close() {\n this.#isOpen = false;\n this.#updateElements();\n\n postbox.dispatchEvent(new CustomEvent('dialog-closed', { detail: { dialog: this } }));\n }\n\n #updateElements() {\n const isOpen = this.#isOpen;\n const targetElement = this.#targetElement;\n targetElement.classList.toggle('open', isOpen);\n\n if(isOpen) {\n lockFocus(targetElement);\n lockScroll();\n targetElement.focus();\n } else {\n unlockFocus();\n unlockScroll();\n this.#openedFromElement?.focus();\n }\n\n const activatorElements = this.#getActivatorElements();\n for(const activatorElement of activatorElements) {\n activatorElement.setAttribute('aria-expanded', isOpen.toString());\n }\n }\n\n #generateUniqueElementId(baseId) {\n let id = baseId;\n let i = 1;\n\n while(!!document.getElementById(id)) {\n id = `${baseId}-${i++}`;\n }\n\n return id;\n }\n\n #getActivatorElements() {\n const targetElement = this.#targetElement;\n const elements = [...document.querySelectorAll('[data-dialog-activator]')];\n return [\n ...elements.filter(element => element.dataset.dialogActivator === targetElement.id),\n ...this.#getCloseButtons()\n ];\n }\n\n #getCloseButtons() {\n const targetElement = this.#targetElement;\n const elements = [...document.querySelectorAll('[data-dialog-close-button]')];\n return elements.filter(element => element.dataset.dialogcCloseButton === targetElement.id || targetElement.contains(element));\n }\n}\n","import { firstAnscestorOrDefault } from './dom-utils.mjs';\nimport Dialog from './dialog.mjs';\nimport postbox from '../postbox.mjs';\n\nexport class DialogManager {\n /**\n * @type {Dialog[]}\n */\n #dialogs = [];\n\n #handleClickBound = null;\n\n constructor() {\n this.#handleClickBound = this.#handleClick.bind(this);\n\n this.#setupEventListeners();\n this.#registerDialogs();\n }\n\n reset() {\n for(const dialog of this.#dialogs) {\n dialog.destroy();\n }\n\n this.#dialogs = [];\n }\n\n #setupEventListeners() {\n document.addEventListener('click', this.#handleClickBound);\n }\n\n dispose() {\n this.reset();\n document.removeEventListener('click', this.#handleClickBound);\n }\n\n #registerDialogs() {\n const dialogElements = document.querySelectorAll('[data-register-dialog]');\n for(const element of dialogElements) {\n this.addDialog(element);\n }\n }\n\n #handleClick(event) {\n const targetElement = event.target;\n const elementWithDialogActivator = firstAnscestorOrDefault(targetElement, element => typeof element.dataset.dialogActivator !== 'undefined', true);\n const activatorElementId = elementWithDialogActivator?.dataset.dialogActivator;\n\n if(!!activatorElementId) {\n const dialogElement = document.getElementById(activatorElementId);\n if(!!dialogElement) {\n this.openDialog(dialogElement, elementWithDialogActivator);\n }\n }\n\n const elementWithDialogClose = firstAnscestorOrDefault(targetElement, element => typeof element.dataset.dialogCloseButton !== 'undefined', true);\n const closeElementId = elementWithDialogClose?.dataset.dialogCloseButton;\n\n if(!!closeElementId) {\n const dialogElement = document.getElementById(closeElementId);\n if(!!dialogElement) {\n this.closeDialog(dialogElement);\n }\n }\n }\n\n addDialog(targetElement) {\n const dialog = new Dialog(targetElement);\n this.#dialogs.push(dialog);\n }\n\n openDialog(targetElement, sourceElement) {\n const dialog = this.#dialogs.find(dialog => dialog.element === targetElement);\n if(!dialog) {\n console.warn('No dialog found for targetElement.', targetElement);\n return;\n }\n\n dialog.open(sourceElement);\n\n postbox.dispatchEvent(new CustomEvent('dialog-opened', { detail: { dialog, sourceElement } }));\n }\n\n closeDialog(targetElement) {\n const dialog = this.#dialogs.find(dialog => dialog.element === targetElement);\n if(!dialog) {\n console.warn('No dialog found for targetElement.', targetElement);\n return;\n }\n\n dialog.close();\n\n postbox.dispatchEvent(new CustomEvent('dialog-closed', { detail: { dialog } }));\n }\n}\n\nexport default new DialogManager();\n","import '../styles/main.scss';\n\nimport initBlocks from './block-scripts/init.mjs';\nimport initPageScripts from './page-scripts/init.mjs';\nimport initPages from './pages/init.mjs';\nimport './utils/dialog-manager.mjs';\n\ninitPageScripts();\ninitBlocks();\ninitPages();\n"],"file":"assets/index-oNf1xAe0.js"}